描述
Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗?
-
输入
- 有多组测试数据
每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和Vi。
(1<=k=n<=10000) (1<=Wi,Vi<=1000000)
输出 - 输出使得单位价值的最大值。(保留两位小数) 样例输入
-
3 2 2 2 5 3 2 1
样例输出 -
0.75
-
-
**在开始看代码之前,你需要了解三个东西,1.贪心,2.二分,3.0-1分数规划,前两个应该都知道,但是第3个东西,那可要好好的说一说
-
//sigma()来表示数学上的求和公式 链接 http://m.blog.youkuaiyun.com/article/details?id=8883652
-
这个第一个问题解释的十分详细,初中水平的数学就就能看懂的,这里就不多解释了
-
-
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int n,k; int v[10010],w[10010]; double dp[10010];//这个数组用来存我们方程子元素的结果的 int compare(double a,double b)//sort函数的比较函数,从大到小 { return a>b; } bool judge(double l)//判断当前是否为最优解,然后通过二分压缩区间 { int i; double sum = 0; for(i=0;i<n;i++) dp[i] = v[i]-l*w[i];//这就是通过上面的 0-1分数规划求出来的方程,可不是你想的随随便便就写出来的 sort(dp,dp+n,compare); for(i=0;i<k;i++)//对前k项子项求和 ,当sum的值趋近于 0 的时候,传入的mid就是最优解了 sum+=dp[i]; if(sum>=0)//如果sum>0 说明我们没有充分发挥价值,还要剩余,sum=0的话我们也试试能不能再大一点 return true;//简单来说就是mid取到一个极大值,任何比mid大的值都会使sum<0 else return false;//这种情况下对应的就是我们所找的mid大于我们的实际最优解,实际上这个值是取不到的,也是没有意义的 } int main() { int i; while(~scanf("%d%d",&n,&k)) { double max = 0; for(i=0;i<n;++i) { scanf("%d%d",&w[i],&v[i]); max = v[i]*1.0/w[i] > max? v[i]*1.0/w[i] : max;//我们计算出每个物品的平均价值,最优解的范围就在 0到最大平均价值之间,这应该很容易懂的吧 } double low=0,high=max,mid;//二分搜索最优解,下界0,上界max(最大的单位价值) while(high-low>0.00001)//注意对double类型的二分判断条件是小于0.00001,不懂的就去百度一下 { mid = (low+high)/2; if(judge(mid))//通过judge函数来压缩区间 low = mid; else high = mid; } printf("%.2lf\n",mid);//保留两位输出就好 } return 0; }
-
-
-
下面是纯代码
-
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int n,k; int v[10010],w[10010]; double dp[10010]; int compare(double a,double b) { return a>b; } bool judge(double l) { int i; double sum = 0; for(i=0;i<n;i++) dp[i] = v[i]-l*w[i]; sort(dp,dp+n,compare); for(i=0;i<k;i++) sum+=dp[i]; if(sum>=0) return true; else return false; } int main() { int i; while(~scanf("%d%d",&n,&k)) { double max = 0; for(i=0;i<n;++i) { scanf("%d%d",&w[i],&v[i]); max = v[i]*1.0/w[i] > max? v[i]*1.0/w[i] : max; } double low=0,high=max,mid; while(high-low>0.00001) { mid = (low+high)/2; if(judge(mid)) low = mid; else high = mid; } printf("%.2lf\n",mid); } return 0; }
-
奈何我冒泡的算法如果打动你超时的心!!