标签:style blog http color for 2014 div 问题 代码
【故事】
------------------------------------------------
【思考】
抽象出来两个问题:
1. 有一个序列X = {X1, X2, ..., Xn}。对于X的任意子集X′ = {xi | xi∈X},求Min(ΣX′) > Y(Y是一个阈值)。也就是就一个子序列,满足两个条件:
(1)子序列之和要大于Y
(2)满足条件(1)中和最小的子集
2. 对于上面求出来的子序列Xk = {xi | xi∈X},设ΣXk = S, R = S - Y。证明肯定存在一个xi(xi∈Xk)满足:xi >= R。
你也先别看,思考一下有什么好的办法去解决这个问题,高手有什么别的建议或者更好的办法也希望能分享给小弟,多谢!^_^
【思路】
1. 问题1
整体的思路如下:
(1)想到背包问题,但是有一点不一样。背包问题是刚好小于背包的大小,而这题是大于。但是还是非常符合动态规划的子问题重叠,但是一直没转换成动态规划解题。
(2)分而治之。朋友的思路。
(3)第二天一早,朋友就给我电话,说可以这样:背包问题是求给定大小下的最大价值问题,此题反过来思考就是一个背包问题,把序列和减去阈值,然后求满足这个容量的背包问题,最后没有被选中的就是此题的结果!直接大赞啊!^_^
2. 问题2
想了一会,然后想到反证法,也就很快看到结果了。毫无疑虑的往下写代码了。
证明:
设x1+x2+...+xn >= Y,并且x1+x2+...+xn-xi < Y(i=1,n), R = x1+x2+...+xn - Y
假设不存在一个xi 满足xi >= R,即所有的xi(i=1,n), 都有xi > R
因为x1+x2+...+xn-xi < Y
所以x1+x2+...+xn < Y+xi < Y+R
与x1+x2+...+xn = Y+R矛盾
所以证明成立!
【结果】
逻辑没有问题了,问题也就迎仍而解了!还是贴一段代码(参考网上改动了一点内容)
typedef struct _tagLYGoods { int nValue; int nWeight; }LYGoods; int LYMax(int a, int b) { return ((a > b) ? a : b); } int LYPrintPack(int **c, LYGoods *A, int nItem, int nSize, std::vector<int> &vecRet) { int *Ret = new int[nItem]; for (int i = 0; i < nItem; i++) Ret[i] = 0; for (int i = nItem; i > 0; i--) { if (c[i][nSize] > c[i - 1][nSize]) { Ret[i - 1] = 1; nSize -= A[i - 1].nWeight; } } cout << "PrintPack: " << endl; for (int j = 0; j < nItem; j++) { if (Ret[j] == 0) vecRet.push_back(j); cout << Ret[j] << ", " << A[j].nWeight << ";"; } cout << endl; delete[] Ret; return true; } int LYPack(LYGoods *A, int nItem, int nSize, std::vector<int> &vecRet) {int **MN = new int*[nItem + 1]();//定义一维动态数组 for (int i = 0; i<nItem + 1; i++)//用循环令一维数组变成二维 { MN[i] = new int[nSize + 1]; } int nMax = 0; for (int i = 0; i < nItem; i++) for (int j = 0; j < nSize; j++) MN[i][j] = 0; for (int i = 1; i <= nItem; i++) { for (int j = 1; j <= nSize; j++) { if (j < A[i - 1].nWeight) { MN[i][j] = MN[i - 1][j]; } else { MN[i][j] = LYMax(MN[i - 1][j], MN[i - 1][j - A[i - 1].nWeight] + A[i - 1].nValue); } } } LYPrintPack(MN, A, nItem, nSize, vecRet); int nRet = MN[nItem][nSize]; for (int i = 0; i<nItem + 1; i++) { delete[] MN[i]; } return nRet; }
(1)结果:
序列:2, 11, 15, 20, 32, 阈值:31
得到的结果是:11, 20
(2)随机结果:
【总结】
1. 很高兴碰到一个这样的问题,而且静下心来去解决
2. 交流是很重要的,比一个人学习的收益要大很多^_^
3. 动态规划还真是没有搞懂!继续学习!
标签:style blog http color for 2014 div 问题 代码
原文地址:http://www.cnblogs.com/pk-run/p/3883908.html