【求助】一个算法

jthkl 2019-01-16 10:25:33
一直手里有108张发票,以及每张发票的金额,已知其中N张的金额合计是266270.83,怎样把这N张挑出来。
...全文
5522 55 打赏 收藏 转发到动态 举报
写回复
用AI写文章
55 条回复
切换为时间正序
请发表友善的回复…
发表回复
shuishui312 2019-02-02
  • 打赏
  • 举报
回复
厉害了
wdonghai 2019-01-28
  • 打赏
  • 举报
回复
弄错了IndexOf的返回值,以为找不到的时候返回0,
if (RsList.IndexOf(s) > 0) return;//剔除重复结果
应该改为
if (RsList.IndexOf(s) !=-1) return;//剔除重复结果
wdonghai 2019-01-25
  • 打赏
  • 举报
回复

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const double cSum=266270.83;//目标值
private List<double> dataList;
private List<String> RsList;
private int gRsCount = 0;//答案个数
private int gBegin = 0;//计时开始
private double[] data;

private void dfs(int n, int b, double m)
{
if (gRsCount>=100) return;//100个答案就退出,如果要求所有答案,注释掉此行
if (m<0) return;
if (Math.Round(m * 1000) == 0)//按照3位小数比较,比较2位小数就乘以100,当初直接用m==0来比较,结果错过了答案
{
List<double> aRs = new List<double>();//保存结果
for (int i = 1; i <= b - 1; i++)
{
if (data[i] > 0)
{
aRs.Add(data[i]);
}
}

aRs.Sort();
//同一个结果集里面,数据位置不同,但是数据集相加的结果还是等于目标数值,会出现结果集重复,需要剔除
//例如1+2+3=6,1+3+2=6,两个答案只需保留一个
StringBuilder sRs = new StringBuilder();
StringBuilder sRs2 = new StringBuilder();
for (int i = 0; i < aRs.Count; i++)
{
sRs2.Append("\r\n"+(aRs[i].ToString()));
sRs.Append(" " + aRs[i].ToString());
}
String s = sRs.ToString();
if (RsList.IndexOf(s) > 0) return;//剔除重复结果
RsList.Add(s);
gRsCount++;
textBox1.AppendText("\r\n用时 " + (System.Environment.TickCount - gBegin).ToString() + " 毫秒");
textBox1.AppendText("找到第 " + gRsCount.ToString() + " 个解 : ");
textBox1.AppendText(sRs2.ToString());
textBox1.AppendText("\r\n");
return;
}

for (int i = b; i <= n - 1; i++)
{
double d = dataList[i];
data[b] = d;
dfs(n, i + 1, m - d);
data[b] = 0;
}
}

private void button1_Click(object sender, EventArgs e)
{
dataList = new List<double>();
RsList = new List<string>();
StreamReader sr = new StreamReader("./data.txt", Encoding.Default);
String line;
while ((line = sr.ReadLine()) != null)
{
dataList.Add(double.Parse(line));
}

//升序或者降序需要根据目标值来定,目标值大就按降序,目标值小就按升序
dataList.Sort((x, y) => -x.CompareTo(y));
dataList.Insert(0, 0);//下标从1开始参与计算

gRsCount = 0;
textBox1.Text = "计算中...";
textBox1.AppendText("\r\n");
gBegin = System.Environment.TickCount;
data = new double[dataList.Count];
dfs(dataList.Count, 1, cSum);
textBox1.AppendText("\r\n计算完成...");
}
}
森狗道格 2019-01-22
  • 打赏
  • 举报
回复
先遍历知道每个发票金额,然后排序,从最小的开始挨个加求和。
  • 打赏
  • 举报
回复
这么简单的递归算法(可以看相关代码)不会写,不会c#/.net 已经本基本的迭代器编程技术,那么数学差、数据结构/算法知识不合格,对于 c#/.net 的知识也不符合最近10年技术水平。
  • 打赏
  • 举报
回复
枚举的算法,也得写出来。我们这里招聘 .net 服务器开发程序员,这类问题是最基本的上机考试题。
qq_30407229_lily 2019-01-19
  • 打赏
  • 举报
回复
动态规划似乎能解决这个问题
张天星 2019-01-19
  • 打赏
  • 举报
回复
引用 21 楼 weixin_44420730 的回复:
[quote=引用 16 楼 wanghui0380 的回复:]
没有算法,NP问题是世界难题。在你这个条件下,可以是全组合,可以是贪婪回溯,可以是先算分布预测回归再试算回溯。但是其实都算暴力枚举,你这条件少,基本可以算。条件在多点,就得喊数学家来搞了


我觉得你说的不对[/quote]
他说的没问题啊,就是暴力枚举,没啥捷径啊
  • 打赏
  • 举报
回复
就这个问题而言,“用大额的凑”基本上没多大优化改进意义,因为目标值太大,而可用的发票金额普遍都很小。
weixin_44573854 2019-01-19
  • 打赏
  • 举报
回复
先用大额的凑,排除
grainrain1 2019-01-19
  • 打赏
  • 举报
回复
呵呵
grainrain1 2019-01-19
  • 打赏
  • 举报
回复
我觉得很好恩恩
m0_37575387 2019-01-18
  • 打赏
  • 举报
回复
我也想看看怎么算
  • 打赏
  • 举报
回复
引用 40 楼 654016803 的回复:
看不太董不明白,不知道怎么算
“查询”方法中两个 foreach 语句,很简单。 关键是递归,或者说归纳,或者说是数学训练有基础。
  • 打赏
  • 举报
回复
并不是 108 这个数太多,而是目标值很大,而适合这个目标值的待选的发票太多。比如说要查目标值几千、几百的,输出几十个方案,也非常快!
loveljy_19901114 2019-01-18
  • 打赏
  • 举报
回复
108实在太多了,要实现的话估计得执行好久
  • 打赏
  • 举报
回复
引用 48 楼 jthkl的回复:
不倒半分钟就 OutOfMemoryException 啦
哈哈,内存越界了,实在不行用spark试试
  • 打赏
  • 举报
回复
引用 37 楼 陌上寒清的回复:
重大到小,先知道最少会有多少张,然后,就用循环不停的计算,
这是最笨的方法了。。。。
654016803 2019-01-18
  • 打赏
  • 举报
回复
看不太董不明白,不知道怎么算
jthkl 2019-01-18
  • 打赏
  • 举报
回复
不倒半分钟就 OutOfMemoryException 啦
加载更多回复(35)

110,536

社区成员

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

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

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