poj 3111 K Best ,二分,牛顿迭代
来源:互联网 发布:电影推荐知乎2015 编辑:程序博客网 时间:2024/05/23 07:24
poj 3111 K Best
有n个物品的重量和价值分别是wi和vi。从中选出k个物品使得单位重量的价值最大。
题解:
1、二分做法
2、牛顿迭代
效率比较:
二分做法:
转换成判断是否存在选取K个物品的集合S满足下面的条件:
sigma(vi) / sigma(wi) >= x {vi∈S, wi∈S}
--> simga(vi - x*wi) >= 0
这样我们对 yi= vi - x*wi {1<=i<=n}从大到小排序,计算sum(yi) {1<=i<=k}
如果sum(yi){1<=i<=k}>=0 ,则说明 sigma(vi) / sigma(wi) >= x, 成立。
那么我们只要二分x {注意精度},就能找到单位重量价值最大的k个物品。
#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100000 + 10;const int INF = 1e7;int v[maxn], w[maxn];struct node { double val; int id; bool operator < (const node& rhs) const { return val > rhs.val; }};node f[maxn];int ans[maxn];int n, k;//sigma(vi)/sigma(wi) >= x//-> sigma(vi - x*wi) >= 0int ok(double x) { for(int i=0; i<n; ++i) { f[i].val = v[i] - x*w[i]; f[i].id = i+1; } sort(f, f+n); double sum = 0; for(int i=0; i<k; ++i) { sum += f[i].val; ans[i] = f[i].id; } return sum >= 0;}int main() { scanf("%d%d", &n, &k); for(int i=0; i<n; ++i) { scanf("%d%d", &v[i], &w[i]); } double l = 0, r = INF; //for(int i=0; i<50; ++i) { while(r-l>1e-8){ double mid = (l+r)/2; if(ok(mid)) l = mid; else r = mid; } for(int i=0; i<k; ++i) { printf("%d", f[i].id); if(i<k-1) printf(" "); else printf("\n"); } return 0;}
牛顿迭代
关于牛顿迭代法详见:点击打开链接
先取前k个元素算出S0 =∑(vi/wi) 作为初始值
然后对每一个元素(n个)求yi=vi-s0*wi
对yi从大到小排序,取前k个元素算出S,
重复上面的运算(每次循环后把S的值赋给S0,然后新一轮循环时S有通过S0计算出来),直到fabs(S-S0)<=eps,满足精度要求。
正确性证明:
证明其正确性,只要证明每次迭代的S都比上一次的大即可,也即迭代过程中S是单调递增的,因为给定的是有限集,故可以肯定,S必存在最大值,即该迭代过程是收敛的。下面证明单调性:
假设上轮得到的S1,则在n个元素中必存在k个元素使S1=∑(vi/wi),变形可得到∑vi-S1*∑wi=0,
现对每个元素求yi=vi-S1*wi,可知必存在k个元素使∑yi=∑vi-s1*∑wi=0, 所以当我们按y排序并取前k个元素作为求其∑y时,其∑y>=0,
然后对和式变形即可得到S1=((∑v-∑y)/∑w)<=(∑v/∑w)=s2,即此迭代过程是∑y是收敛的,当等号成立时,此S即为最大值。
#include<cstdio>#include<cmath>#include<algorithm>using namespace std;const int maxn = 100000 + 10;const double eps = 1e-8;int v[maxn], w[maxn];struct node { double val; int v, w; int idx; bool operator < (const node& rhs) const { return val > rhs.val; }};node f[maxn];int n, k;double Get() { double sumv = 0, sumw = 0; for(int i=0; i<k; ++i) { sumv += f[i].v; sumw += f[i].w; } return sumv/sumw;}int main() { scanf("%d%d", &n, &k); for(int i=0; i<n; ++i) { scanf("%d%d", &f[i].v, &f[i].w); f[i].idx = i+1; } double s1, s2 = Get(); do { s1 = s2; for(int i=0; i<n; ++i) { f[i].val = f[i].v - s1*f[i].w; } sort(f, f+n); s2 = Get(); } while(fabs(s2-s1)>=eps); for(int i=0; i<k; ++i) { printf("%d%c", f[i].idx, " \n"[i==n-1] ); } return 0;}
- poj 3111 K Best ,二分,牛顿迭代
- poj 3111 K Best 【0-1分数规划】 【二分 or Dinkelbach迭代】
- poj 3111 K Best 二分
- poj 3111 K Best 参数搜索之牛顿迭代法
- POJ 3111 - K Best(二分搜索)
- POJ 3111 K Best <最大化平均,二分>
- poj 3111 K Best(二分)
- POJ 3111 K Best 【二分:最大化平均值】
- POJ 3111 K Best 二分 最大化平均值
- POJ 3111:K Best(思维+二分)
- K Best poj 3111 (01分数规划---二分搜索)
- POJ 2976 Dropping tests、3111 K Best (二分搜索)
- POJ 3111 K Best (01分数规划+二分)
- POJ 3111 K Best(二分搜索,最大化平均值)
- POJ - 3111 K Best (二分 + 01分数规划)
- poj3111- POJ - 3111 K Best (二分 + 01分数规划)
- POJ 3111 K Best 二分(最小化平均值)
- poj 3111 K Best 二分搜索 最大化平均值
- Sed使用的变量里含有转义字符的解决
- Java面向对象——多态
- solr 相似查询 -- MoreLikeThis
- hdoj 1045 Fire Net 【DFS】
- 把安卓源码中的system app独立出来,像开发普通app那样开发
- poj 3111 K Best ,二分,牛顿迭代
- Linux文件系统启动过程及login的实现
- 设计模式(三)单例模式
- iOS开发1小时快速入门
- 第九章 9.2.7节练习
- 华为机试题(字符串处理集锦)
- 武汉治疗银屑病
- 设计模式(四)策略模式
- 武汉哪里治牛皮癣