2013编程之美挑战赛复赛---R2_B:招聘(01分数规划+DP)
2013-09-08 11:04
429 查看
总Time Limit: 6000ms Memory Limit: 262144kB
Description
Alice新开了一家公司,它的下面有两个项目,分别需要N1和N2个人来完成。现在有N个人前来应聘,于是Alice通过面试来决定他们中的哪些人会被录用。
Alice在面试中,会仔细考察他们能如何为公司的项目带来收益。她给每个人打了两个分值Q1和Q2,表示他加入第一个和第二项目分别能带来的收益值。同时,她也会仔细考察他们每个人的缺点,并且给每人打了另两个分值C1和C2,表示他们进入每个项目可能带来的负面效应。Alice心目中的最优决策是,在决定好录用哪些人以及每个人在哪个项目下工作之后,他们为公司带来的收益总和,除以他们为项目带来的负面效应总和,这个比值要最大。你能帮他计算出在最优决策下,这个比值为多少吗?
前来应聘的人数总是大于等于两个项目需求人数的总和,因此Alice一定会恰好招N1+N2个人,分配给第一个项目N1个人,分配给第二个项目N2个人,没有人会同时属于两个项目。
Input输入文件包含多组测试数据。
第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。
每组数据第一行为三个用空格隔开的整数N,N1,N2,表示前来应聘的人数,以及两个项目分别需要的人数。
接下来N行,每行是用空格隔开的四个整数Q1,C1,Q2,C2,依次表示每个人在第一个项目下的价值和负面效应,以及第二个项目下的价值和负面效应。
T ≤ 100
1 ≤ Q1, Q2 ≤ 2000
1 ≤ C1, C2 ≤ 50
小数据:0 < N1 + N2 ≤ N ≤ 50,
大数据:0 < N1 + N2 ≤ N ≤ 500
Output对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最优决策下招募的人的价值总和与负面效应总和的比值,与正确答案的绝对误差不应超过10-6。所有数据按读入顺序从1开始编号。
Sample Input
Sample Output
可以去AC的地方:http://msbop.openjudge.cn/bop2013/R2_B/[/code]
Description
Alice新开了一家公司,它的下面有两个项目,分别需要N1和N2个人来完成。现在有N个人前来应聘,于是Alice通过面试来决定他们中的哪些人会被录用。
Alice在面试中,会仔细考察他们能如何为公司的项目带来收益。她给每个人打了两个分值Q1和Q2,表示他加入第一个和第二项目分别能带来的收益值。同时,她也会仔细考察他们每个人的缺点,并且给每人打了另两个分值C1和C2,表示他们进入每个项目可能带来的负面效应。Alice心目中的最优决策是,在决定好录用哪些人以及每个人在哪个项目下工作之后,他们为公司带来的收益总和,除以他们为项目带来的负面效应总和,这个比值要最大。你能帮他计算出在最优决策下,这个比值为多少吗?
前来应聘的人数总是大于等于两个项目需求人数的总和,因此Alice一定会恰好招N1+N2个人,分配给第一个项目N1个人,分配给第二个项目N2个人,没有人会同时属于两个项目。
Input输入文件包含多组测试数据。
第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。
每组数据第一行为三个用空格隔开的整数N,N1,N2,表示前来应聘的人数,以及两个项目分别需要的人数。
接下来N行,每行是用空格隔开的四个整数Q1,C1,Q2,C2,依次表示每个人在第一个项目下的价值和负面效应,以及第二个项目下的价值和负面效应。
T ≤ 100
1 ≤ Q1, Q2 ≤ 2000
1 ≤ C1, C2 ≤ 50
小数据:0 < N1 + N2 ≤ N ≤ 50,
大数据:0 < N1 + N2 ≤ N ≤ 500
Output对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最优决策下招募的人的价值总和与负面效应总和的比值,与正确答案的绝对误差不应超过10-6。所有数据按读入顺序从1开始编号。
Sample Input
1 5 2 2 12 5 8 3 9 4 9 4 7 3 16 6 11 5 7 5 18 10 6 3
Sample Output
Case #1: 2.444444
解题思路 这是一道典型的01分数规划问题,我们想要求这样一个函数的最大值 f(x)/g(x)(g(x)>0), 我们只需找到最小的r,使得存在x满足h(x)=f(x)-r*g(x)>=0,这个r即为解。而这个r可以通过二分来确定。我们现在只需在给定r的条件下,求解f(x)-r*g(x)的最大值即可。 在这道问题中,f(x)=sum(Q1[i])+sum(Q2[j]) (i in S1, j in S2),g(x)=sum(C1[i])+sum(C2[j]) (i in S1, j in S2), 我们需要确定出两个集合S1,S2,使得f(x)-r*g(x)最大,即h(x)=sum(Q1[i]-r*C1[i])+sum(Q2[j]-r*C2[j])(i in S1, j in S2)。这里我们只需用动态规划来求解。令f[i][j][k]表示,在前i个人之中,有j个人属于S1,有k个人属于S2,此时最大的h(x)函数值为多少,转移很好考虑,即下一个人分在哪个项目或者不招进来。这样便能找到最大的h(x)。 仅仅做到这里还是不够,考虑到数据范围,这种做法可能会超时。一种优化思路是,当S1集合的人定下来时时,S2集合中的人一定可以贪心地选择剩余人中Q2[j]-r*C2[j]值最大的前N2个人,由此我们修改这个算法,先将所有人按Q2[j]-r*C2[j]从大到小排序,然后令f[i][j]表示前i个人之中,有j个人属于S2,并且不属于S1的人自动选前N2个人属于S2,此时h(x)的最大值。转移方式类似。如此一来,时间复杂度会下降一个阶,可以解决这道题目。 代码:
#include<iostream> #include<cstring> #include<cstdlib> #include<fstream> #include<algorithm> using namespace std; typedef pair<double,double> PR; const int MAXN=505; int Q1[MAXN],C1[MAXN],Q2[MAXN],C2[MAXN]; //dp[i][j]:= 前i个人中,有j个人去第二个项目,此时最大的 h double dp[MAXN][MAXN]; PR h[MAXN]; int n,n1,n2; bool Cmp(PR a,PR b){ if(a.first!=b.first) return a.first>b.first; return a.second>b.second; } bool isok(double mid) { for(int i=1;i<=n;i++){ h[i].first=Q1[i]-mid*C1[i]; h[i].second=Q2[i]-mid*C2[i]; } sort(h+1,h+1+n,Cmp); double ans=0.0; dp[0][0]=0; for(int i=1;i<=n;i++){ dp[i][0]=dp[i-1][0]+(i<=n1)*h[i].first; for(int j=1;j<i&&j<=n2;j++){ dp[i][j]=max(dp[i-1][j]+(i-j<=n1)*h[i].first,dp[i-1][j-1]+h[i].second); } if(i<=n2) dp[i][i]=dp[i-1][i-1]+h[i].second; } for(int i=n1+n2;i<=n;i++) ans=max(ans,dp[i][n2]); //cout<<ans<<endl; return ans>0; } void solve() { double l=0,r=20000; while(r-l>0.000001) { double mid=(l+r)/2; if(isok(mid)) l=mid; else r=mid; } printf("%.6f\n",(l+r)/2); } int main() { int t,ca=1; cin>>t; while(t--) { cin>>n>>n1>>n2; for(int i=1;i<=n;i++){ cin>>Q1[i]>>C1[i]>>Q2[i]>>C2[i]; } cout<<"Case #"<<ca++<<": "; solve(); } return 0; }
可以去AC的地方:http://msbop.openjudge.cn/bop2013/R2_B/[/code]
相关文章推荐
- Codeforces 489E Hiking(普通01分数规划加DP)
- bzoj 4501: 旅行 01分数规划+概率期望dp
- BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)
- BZOJ 4753 [Jsoi2016]最佳团体 ——01分数规划 树形DP
- 2013-BIT程序设计 12.编程珠玑 -- dp
- Dropping tests(01分数规划+spfa判断负权还)
- POJ 2728 01分数规划
- HDU 4530 小Q系列故事——大笨钟 2013腾讯编程马拉松复赛第一场第一题
- 编程之美 2013 全国挑战赛 初赛第一场 题目二 相似字符串
- poj3155 Hard Life 【最大密度图 01分数规划】
- 【ZOJ2676】Network Wars 最小割+01分数规划
- 01分数规划zoj2676(最优比例,最小割集+二分)
- POJ 2728 Desert King | 01分数规划
- [Algorithm]01分数规划(转)(C++代码)
- 01分数规划问题
- 【POJ 2976】Dropping tests&01分数规划详解
- POJ - 2976 Dropping tests 01分数规划
- 01分数规划
- 【BZOJ1486】[HNOI2009]最小圈【SPFA判负环】【01分数规划】
- POJ 2976 Dropping tests(普通01分数规划)