问一个算法的问题

CppPower 2010-08-21 09:30:26
组出一个总数T,一个参与计算的次数N,与一组数字L
从L里选择数字相加N次,等于T,并列出这些数字参与的次数

举例
T=30
N=5
L:1,2,3,5,6,7,8,9,10

要从1,2,3,5,6,7,8,9,10里选择数字相加5次,相加等于30

可能的结果有 5 + 5 + 5 + 5 + 10 =30
5参与4次计算
10参与1次计算

可能的结果有 10 + 10 + 2 + 3 + 5 = 30
10参与2次计算
2参与1次计算
3参与1次计算
5参与1次计算

麻烦啊
...全文
186 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
shukinwg 2010-08-22
  • 打赏
  • 举报
回复
我以为楼主的题目不够明确。数T,N,数组(假设a[L])长度L以及数组a[i](i=0,1,2,...L-1)的取值范围等都没有说明。另外,上面的T,N,a[L]都是一般代数,还是象你举的例子一样都是一些具体的整数?不得而知。如果是一般代数问题,那么它的求解很困难。下面以楼主举的具体数例为题求解吧。不一定对。
要从a[11]=0,1,2,3,4,5,6,7,8,9,10(L=10)里选择数字相加N=5次,其和T=30。列出这些数字参与的次数p[i],(p[i]表示数字i出现的次数)。注:为了使a[i]=i.故意在前面加了一个并不使用的数0.
分析:每个数出现的频次最多是5次,最少是0次。即对于i=1,2,...10,0<=p[i]<=5.只有当a[i]中的数等于T/N=30/5=6时,6才有可能出现最大次数5.
下面是伪C语言。
N=30,L=10,N=5.
for(i=0;i<11;i++) a[i]=i;
//为了记住数组中有哪些数据。我再造一个数组b[].
BOOL b[T+1].
for(i=0;i<=T;i++) b[i]=0; // memset(b,0,N);
for(i=1;i<=L;i++) b[a[i]]=1; //表示数据中有一个数值为a[i].
for(i=1;i<=L,i++) if{a[i]==T/N) 则p[i]=5,其余p[i]=0; // 求出了某个数出现5次的解。
再求“某个数出现4次,另一个数出现1次。当然其余数出现0次了”这种情形的解。
for(i=1;i<=L,i++)
if(b[N-4*a[i])
{p[a[i]]=4;p[N-4*a[i]]=1;} // a[i]出现4次,N-4*a[i]出现1次。
某个数出现4次的解都求完了。
再求“某个数出现了3次,余下的N-3=2个数可能是是同一个数出现了两次也可能是两个不同的数(各出现一次)”这种情形的解。
for(i=1;i<=L;i++)
if(b[(N-3*a[i])/2])
if(a[i]!=T/N) // 不要它,可能有一个解是上面出现5次的一个解。
{ p[a[i]]=3; p[(N-3*a[i])/2]=2;} // a[i]出现了3次,(N-3*a[i])/2出现了2次。
这样3次+2次的解全求出来了。
再求3次+1次+1次的解。//3+1+1的解。
for(i=1;i<=L;i++) for(j=i+1;j<=L;j++)
if(b[N-3*a[i]-a[j]])
{ p[a[i]]=3;p[a[j]]=1; p[N-3*a[i]-b[j]]=1;}

// 2+1+1+1 即最多了2个重。
for(i=1;i<=L;i++) for(j=i+1;j<=L;j++) for(k=j+1;k<=L;k++)
if(b[(N-a[i]-a[j]-a[k])/2])
{ p[a[i]]=p[a[j]]=p[a[k]]=1; p[(N-a[i]-a[j]-a[k])/2]=2;}

// 1+1+1+1+1

for(i=1;i<=L;i++) for(j=i+1;j<=L;j++)
for(k=j+1;k<=L;k++) for(m=k+1;m<=L;m++)
if(b[N-a[i]-a[j]-a[k]-a[m]])
p[a[i]]=p[a[j]]=p[a[k]]=p[a[m]]=p[N-a[i]-a[j]-a[m]-a[k]]=1;
-----------over(完)----------------------------------------------
对于这个数例,计算量不大。如果数据多时,计算量会增加。
CppPower 2010-08-22
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 litaoye 的回复:]

求全部解还是求解的个数或是任意一个解都可以?

求全部解用搜索,求解的个数或一个解用背包。如果范围是实数,就只能用搜索了。
[/Quote]
只要一个解就行了
shukinwg 2010-08-22
  • 打赏
  • 举报
回复
你那个例题,我不是给你解决了吗?没有看到上面我写的代码(伪C语言)吗?你又不给出实际数据,还希望别人怎么做?
绿色夹克衫 2010-08-22
  • 打赏
  • 举报
回复
给一个比较弱的,只能解决很小规模数据的,因为是求准确解,没有加分支限界,只是做了一些简单的剪枝工作。


using System;

namespace CSharpTest
{
class Program
{
static double[] Items;
static int[] SelectCounter;

public static void Main()
{
Items = new double[] { 167.83, 167.84, 218.43, 101.37, 110.77, 136.32, 136.43, 161.21 };
SelectCounter = new int[Items.Length];
Array.Sort(Items);
double T = 560.6;
int N = 5;

if (Search(N, T, 0))
{
for (int i = 0; i < Items.Length; i++)
if (SelectCounter[i] > 0)
Console.WriteLine("{0}选{1}个", Items[i], SelectCounter[i]);
}
else
Console.WriteLine("无解");

Console.ReadKey();
}

public static bool Search(int remainCount, double remain, int currentIndex)
{
if (currentIndex >= Items.Length)
return false;

//因为是Double 所以需要一个近似
if (Math.Abs(Items[currentIndex] * remainCount - remain) < 0.000000000001)
{
SelectCounter[currentIndex] = remainCount;
return true;
}
else if (Items[currentIndex] * remainCount > remain)
return false;

for (int i = 0; i < remainCount; i++)
{
SelectCounter[currentIndex] = i;
if (Search(remainCount - i, remain - Items[currentIndex] * i, currentIndex + 1))
return true;
}

return false;
}
}
}
CppPower 2010-08-22
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 litaoye 的回复:]

既然不是整数的话,那问一下精度问题!小数点后面几位?
不过如果L只有10个,N不到10个的话,用搜索就可以,也就是上面提到的回溯,配合分支限界就可以。

引用 14 楼 cpppower 的回复:
求全部解还是求解的个数或是任意一个解都可以?

求全部解用搜索,求解的个数或一个解用背包。如果范围是实数,就只能用搜索……
[/Quote]

小数几位都没有关系吧,反正相加得出T就行了
绿色夹克衫 2010-08-22
  • 打赏
  • 举报
回复
既然不是整数的话,那问一下精度问题!小数点后面几位?
不过如果L只有10个,N不到10个的话,用搜索就可以,也就是上面提到的回溯,配合分支限界就可以。

[Quote=引用 14 楼 cpppower 的回复:]
求全部解还是求解的个数或是任意一个解都可以?

求全部解用搜索,求解的个数或一个解用背包。如果范围是实数,就只能用搜索……
[/Quote]
CppPower 2010-08-22
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 litaoye 的回复:]

再多问一下,数据的范围大概是?也就是说T,N,L大概在什么范围之内,如果都比较大的话,动态规划可能不行,需要用一些高级技术。

引用 10 楼 cpppower 的回复:

引用 8 楼 litaoye 的回复:

求全部解还是求解的个数或是任意一个解都可以?

求全部解用搜索,求解的个数或一个解用背包。如果范围是实数,就只能用搜索了。

只要一个解就行了
[/Quote]

T为总数,他的大小其实就是从L中选择数字相加N次,就能得到了
主要就是N和L的值,N的范围不会太大,大概在1--7之间
L的个数也不会很多,10个以内,再举个真实的数据:

T:560.6
N:5
L:167.83
167.84
218.43
101.37
110.77
136.32
136.43
161.21

101.37+101.37+110.77+110.77+136.32=560.6
从L中选择101.37、110.77、136.32相加5次得到560.6
101.37参加2次计算
110.77参加2次计算
136.32参加1次计算

绿色夹克衫 2010-08-22
  • 打赏
  • 举报
回复
再多问一下,数据的范围大概是?也就是说T,N,L大概在什么范围之内,如果都比较大的话,动态规划可能不行,需要用一些高级技术。

[Quote=引用 10 楼 cpppower 的回复:]

引用 8 楼 litaoye 的回复:

求全部解还是求解的个数或是任意一个解都可以?

求全部解用搜索,求解的个数或一个解用背包。如果范围是实数,就只能用搜索了。

只要一个解就行了
[/Quote]
绿色夹克衫 2010-08-22
  • 打赏
  • 举报
回复
求全部解还是求解的个数或是任意一个解都可以?

求全部解用搜索,求解的个数或一个解用背包。如果范围是实数,就只能用搜索了。
CppPower 2010-08-22
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 shukinwg 的回复:]

在数据量不大或者不多时,按照我上面写的方法可求出全部解。
当数据量大或者很多时,用哪种方法都很难求出全部解,因为有可能全部解的结果量就是一个天文数字。
当然,当数据量大时,总是可以找出满足条件的一个解的。而且有很好的算法。例如,遗传算法,****算法等等。(不好意思,故意加*号掩藏其名)。感觉楼主对别人的意见爱理不理的,抱歉,本人不愿意提供源程序了。
[/Quote]

我比较关心你的*是什么内容?背包?动态规划?回朔?
shukinwg 2010-08-22
  • 打赏
  • 举报
回复
在数据量不大或者不多时,按照我上面写的方法可求出全部解。
当数据量大或者很多时,用哪种方法都很难求出全部解,因为有可能全部解的结果量就是一个天文数字。
当然,当数据量大时,总是可以找出满足条件的一个解的。而且有很好的算法。例如,遗传算法,****算法等等。(不好意思,故意加*号掩藏其名)。感觉楼主对别人的意见爱理不理的,抱歉,本人不愿意提供源程序了。
CppPower 2010-08-22
  • 打赏
  • 举报
回复
我查了一下背包算法,我的要求和背包算法有点像,但我的要求里要限制计算次N,也就是说,一定要计算N次
背包算法里只要物品重要小于背包容量就行,没有物品个数的限制
ganchunsaixx 2010-08-21
  • 打赏
  • 举报
回复
穷举我还不会用勒
IMCFDJ 2010-08-21
  • 打赏
  • 举报
回复
楼主想要一个正确的解还是要所有的解?感觉穷举法时间复杂度太大。但是带定义域的多元线性方程好像也没有什么特别好的解法。等待大牛
兔子-顾问 2010-08-21
  • 打赏
  • 举报
回复
穷举。

以前写过一次,Linq,一句出结果的。懒的找了。

你先自己试试写个穷举的。不行再说。
CppPower 2010-08-21
  • 打赏
  • 举报
回复
想不出怎么处理了
穷举??

110,529

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧