POJ1015-Jury Compromise 以及 uva 323正确二维DP解法 (K)
2017-07-25 16:43
113 查看
题目:poj1015
中文描述
在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。选m人的办法是:
控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。输入输入包含多组数据。每组数据的第一行是两个整数n和m,n是候选人数目,m是陪审团人数。注意,1<=n<=200, 1<=m<=20 而且 m<=n。接下来的n行,每行表示一个候选人的信息,它包含2个整数,先后是控方和辩方对该候选人的打分。候选人按出现的先后从1开始编号。两组有效数据之间以空行分隔。最后一组数据n=m=0输出对每组数据,先输出一行,表示答案所属的组号,如 'Jury #1', 'Jury #2', 等。接下来的一行要象例子那样输出陪审团的控方总分和辩方总分。再下来一行要以升序输出陪审团里每个成员的编号,两个成员编号之间用空格分隔。每组输出数据须以一个空行结束。样例输入
样例输出
为叙述问题方便,现将任一选择方案中,辩方总分和控方总分之差简称为“辩控差”,辩方总分和控方总分之和称为“辩控和”。第i 个候选人的辩方总分和控方总分之差记为V(i),辩方总分和控方总分之和记为S(i)。现用f(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案f(j, k)”)的辩控和。并且,我们还规定,如果没法选j 个人,使其辩控差为k,那么f(j, k)的值就为-1,也称方案f(j, k)不可行。本题是要求选出m
个人,那么,如果对k 的所有可能的取值,求出了所有的f(m, k) (-20×m≤ k ≤ 20×m),那么陪审团方案
自然就很容易找到了。
问题的关键是建立递推关系。需要从哪些已知条件出发,才能求出f(j, k)呢?显然,方案f(j, k)是由某个可行的方案f(j-1, x)( -20×m ≤ x ≤ 20×m)演化而来的。可行方案f(j-1, x)能演化成方案f(j, k)的必要条件是:存在某个候选人i,i 在方案f(j-1, x)中没有被选上,且x+V(i) = k。在所有满足该必要条件的f(j-1, x)中,选出 f(j-1, x) + S(i) 的值最大的那个,那么方案f(j-1,
x)再加上候选人i,就演变成了方案 f(j, k)。这中间需要将一个方案都选了哪些人都记录
4000
下来。不妨将方案f(j, k)中最后选的那个候选人的编号,记在二维数组的素path[j][k]中。那么方案f(j, k)的倒数第二个人选的编号,就是path[j-1][k-V[path[j][k]]。假定最后算出了解方案的辩控差是k,那么从path[m][k]出发,就能顺藤摸瓜一步步求出所有被选中的候选人。初始条件,只能确定f(0, 0) = 0。由此出发,一步步自底向上递推,就能求出所有的可行方案f(m, k)( -20×m
≤ k ≤ 20×m)。实际解题的时候,会用一个二维数组f 来存放f(j, k)的值。而且,由于题目中辩控差的值k 可以为负数,而程序中数租下标不能为负数,所以,在程序中不妨将辩控差的值都加上400,以免下标为负数导致出错,即题目描述中,如果辩控差为0,则在程序中辩控差为400。
基本的思路就如上文所说,但是有一个bug需要注意一下,即参考以下的文章:点击打开链接
这道题网上的二维DP标准算法是完全错误的,花了我好几天去思考,后来通过一点点模拟总算找到了错误,且听我慢慢道来,至于错误程序网上有很多,可以去搜索我就不给链接了。
还有,UVA323这道题加强过数据,这才能验证是否是正确的程序。
网上广泛流传的二维DP思路是已经已经选择多少人->此次选择哪个人->差值之和,因为不能重复,所以加入一个判断的过程,
这组数据的答案是
Jury #1
Best jury has value 54 for prosecution and value 54 for defence:
1 2 3 4 6 9
但是错误程序的答案是
Jury #1
Best jury has value 52 for prosecution and value 52 for defence:
1 3 4 5 6 8
warning:我后面讲的数是指一组数据的前面一个数减去后面一个数,加起来指的是这些数加起来,而和指的是一组数据中前一个加后一个。(这样是不是好难理解)这样说比较方便。如这组数据:数分别为{4, 6, -5, 11, 5, -3, 8, -12, -13};加起来指的是4+6或者4+-5这种。和分别是{8,26,13,27,29,11,12,16,23}。务必要看懂这句话。
通过正确的答案和程序,运行得到dp[5][-4+6*20] = 100其中6×20是相当于零点,而-4代表的是第一组数据,9和6,下一个只要是4就可以得出正确的结论,即108。
这个数据是给错误的程序做准备的,因为它不是一个一个枚举,它是通过一个一个去试,然后通过上一个状态寻找该状态该点的最大值。
在错误程序测试dp[5][-4+6*20]也是得到100,这让我赶脚很不对啊
,如果是这样的话,答案怎么可能是52+52=104啊,明显应该108啊。
大牛们肯定已经想到了,一定是因为那个所谓顺藤摸瓜的函数,那5个数之间可能就有第一个数,所以不能选第一个数,所以答案不对,我做出假设,那5个数中间就有第一个数。那么剩下的数之和就为-8。果然找到了。dp[4][-8 + 6*20] = 92,分别是第2,4,8,9个数的和。结果已经出来了。这个程序坑爹的bug已经完全的暴露在我们面前了
。
就是:它无法使几组加起来大小相同,且总的和相同的数据共存!有人可能说,这有什么关系??关系大了,假设答案是一组数据加另外一组数据中的一个数,而程序的 那个位置上选择的是后者。那就永远不可能得出正确答案,这种数据挺难想出来,所以被绝大多数人忽略。
在这里十分佩服 CZDleaf。在题目的discuss里提出了疑问
无疑是正确的,我是一个刚开始做DP的菜鸟,想了好几天才想明白,DP真是个死脑细胞的东西啊。
大牛们肯定一点就通,接下来我就简单说说如何使用2维DP解这道题。灰常简单啊!!(还是问了学长)只要把枚举N组数据放在最外面,里面用逆推,依据背包里的思想。这样就不会有重复,还有关键的一点,就是那个错误程序的bug在这个程序有木有解决,当然解决啦!
在这里数没有那个重复选择的影响,所以假设数字编号135和246是加起来一样,和也一样(和跟加起来是2种意思,看warning),而答案是1356,拿只笔模拟一下就会发觉根本一点关系都没有,因为是顺序的,所有组合都会遍及到不会有覆盖情况,还是因为顺序的所以连sort函数都省了。
其他具体的就看我的AC代码吧~
有问题欢迎大家留言讨论~~
中文描述
在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。选m人的办法是:
控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。输入输入包含多组数据。每组数据的第一行是两个整数n和m,n是候选人数目,m是陪审团人数。注意,1<=n<=200, 1<=m<=20 而且 m<=n。接下来的n行,每行表示一个候选人的信息,它包含2个整数,先后是控方和辩方对该候选人的打分。候选人按出现的先后从1开始编号。两组有效数据之间以空行分隔。最后一组数据n=m=0输出对每组数据,先输出一行,表示答案所属的组号,如 'Jury #1', 'Jury #2', 等。接下来的一行要象例子那样输出陪审团的控方总分和辩方总分。再下来一行要以升序输出陪审团里每个成员的编号,两个成员编号之间用空格分隔。每组输出数据须以一个空行结束。样例输入
4 2 1 2 2 3 4 1 6 2 0 0
样例输出
Jury #1 Best jury has value 6 for prosecution and value 4 for defence: 2 3
为叙述问题方便,现将任一选择方案中,辩方总分和控方总分之差简称为“辩控差”,辩方总分和控方总分之和称为“辩控和”。第i 个候选人的辩方总分和控方总分之差记为V(i),辩方总分和控方总分之和记为S(i)。现用f(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案f(j, k)”)的辩控和。并且,我们还规定,如果没法选j 个人,使其辩控差为k,那么f(j, k)的值就为-1,也称方案f(j, k)不可行。本题是要求选出m
个人,那么,如果对k 的所有可能的取值,求出了所有的f(m, k) (-20×m≤ k ≤ 20×m),那么陪审团方案
自然就很容易找到了。
问题的关键是建立递推关系。需要从哪些已知条件出发,才能求出f(j, k)呢?显然,方案f(j, k)是由某个可行的方案f(j-1, x)( -20×m ≤ x ≤ 20×m)演化而来的。可行方案f(j-1, x)能演化成方案f(j, k)的必要条件是:存在某个候选人i,i 在方案f(j-1, x)中没有被选上,且x+V(i) = k。在所有满足该必要条件的f(j-1, x)中,选出 f(j-1, x) + S(i) 的值最大的那个,那么方案f(j-1,
x)再加上候选人i,就演变成了方案 f(j, k)。这中间需要将一个方案都选了哪些人都记录
4000
下来。不妨将方案f(j, k)中最后选的那个候选人的编号,记在二维数组的素path[j][k]中。那么方案f(j, k)的倒数第二个人选的编号,就是path[j-1][k-V[path[j][k]]。假定最后算出了解方案的辩控差是k,那么从path[m][k]出发,就能顺藤摸瓜一步步求出所有被选中的候选人。初始条件,只能确定f(0, 0) = 0。由此出发,一步步自底向上递推,就能求出所有的可行方案f(m, k)( -20×m
≤ k ≤ 20×m)。实际解题的时候,会用一个二维数组f 来存放f(j, k)的值。而且,由于题目中辩控差的值k 可以为负数,而程序中数租下标不能为负数,所以,在程序中不妨将辩控差的值都加上400,以免下标为负数导致出错,即题目描述中,如果辩控差为0,则在程序中辩控差为400。
基本的思路就如上文所说,但是有一个bug需要注意一下,即参考以下的文章:点击打开链接
这道题网上的二维DP标准算法是完全错误的,花了我好几天去思考,后来通过一点点模拟总算找到了错误,且听我慢慢道来,至于错误程序网上有很多,可以去搜索我就不给链接了。
还有,UVA323这道题加强过数据,这才能验证是否是正确的程序。
网上广泛流传的二维DP思路是已经已经选择多少人->此次选择哪个人->差值之和,因为不能重复,所以加入一个判断的过程,
9 6 6 2 16 10 4 9 19 8 17 12 4 7 10 2 2 14 5 18 0 0
这组数据的答案是
Jury #1
Best jury has value 54 for prosecution and value 54 for defence:
1 2 3 4 6 9
但是错误程序的答案是
Jury #1
Best jury has value 52 for prosecution and value 52 for defence:
1 3 4 5 6 8
warning:我后面讲的数是指一组数据的前面一个数减去后面一个数,加起来指的是这些数加起来,而和指的是一组数据中前一个加后一个。(这样是不是好难理解)这样说比较方便。如这组数据:数分别为{4, 6, -5, 11, 5, -3, 8, -12, -13};加起来指的是4+6或者4+-5这种。和分别是{8,26,13,27,29,11,12,16,23}。务必要看懂这句话。
通过正确的答案和程序,运行得到dp[5][-4+6*20] = 100其中6×20是相当于零点,而-4代表的是第一组数据,9和6,下一个只要是4就可以得出正确的结论,即108。
这个数据是给错误的程序做准备的,因为它不是一个一个枚举,它是通过一个一个去试,然后通过上一个状态寻找该状态该点的最大值。
在错误程序测试dp[5][-4+6*20]也是得到100,这让我赶脚很不对啊
,如果是这样的话,答案怎么可能是52+52=104啊,明显应该108啊。
大牛们肯定已经想到了,一定是因为那个所谓顺藤摸瓜的函数,那5个数之间可能就有第一个数,所以不能选第一个数,所以答案不对,我做出假设,那5个数中间就有第一个数。那么剩下的数之和就为-8。果然找到了。dp[4][-8 + 6*20] = 92,分别是第2,4,8,9个数的和。结果已经出来了。这个程序坑爹的bug已经完全的暴露在我们面前了
。
就是:它无法使几组加起来大小相同,且总的和相同的数据共存!有人可能说,这有什么关系??关系大了,假设答案是一组数据加另外一组数据中的一个数,而程序的 那个位置上选择的是后者。那就永远不可能得出正确答案,这种数据挺难想出来,所以被绝大多数人忽略。
在这里十分佩服 CZDleaf。在题目的discuss里提出了疑问
无疑是正确的,我是一个刚开始做DP的菜鸟,想了好几天才想明白,DP真是个死脑细胞的东西啊。
大牛们肯定一点就通,接下来我就简单说说如何使用2维DP解这道题。灰常简单啊!!(还是问了学长)只要把枚举N组数据放在最外面,里面用逆推,依据背包里的思想。这样就不会有重复,还有关键的一点,就是那个错误程序的bug在这个程序有木有解决,当然解决啦!
在这里数没有那个重复选择的影响,所以假设数字编号135和246是加起来一样,和也一样(和跟加起来是2种意思,看warning),而答案是1356,拿只笔模拟一下就会发觉根本一点关系都没有,因为是顺序的,所有组合都会遍及到不会有覆盖情况,还是因为顺序的所以连sort函数都省了。
其他具体的就看我的AC代码吧~
有问题欢迎大家留言讨论~~
#include<cstdio> #include<ctype.h> #include<algorithm> #include<iostream> #include<cstring> #include<vector> using namespace std; int dp[21][801]; //现用dp(j, k)表示,取j 个候选人,使其辩 //控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案f(j, k)”)的辩控和 vector<int> path[21][801];//记录路径 path[i][j] 取i个人 他们的差为j时候的路径 int main() { int times=1; int subtraction[201],_plus[201]; int n,m,i,j,k; while(~scanf("%d%d",&n,&m) && n && m) { for(i=0;i<m;++i)//清空vector for(j=0;j<801;++j) path[i][j].clear(); memset(dp,-1,sizeof(dp)); int d,p; for(i = 0; i < n; i++) { cin>>d>>p; subtraction[i] = d-p;//差 _plus[i] = d+p;//和 } int fix = 20*m;//该点是平衡点 相当于0点 dp[0][fix] = 0; for(k = 0; k < n; k++)//选择一个 for(i = m-1; i >= 0; i--)//进行逆推 选择几个候选人 { for(j = 0; j < 2*fix; j++)//枚举差的所有范围 { if(dp[i][j] >= 0) { if(dp[i+1][j+subtraction[k]] <= dp[i][j] + _plus[k]) { dp[i+1][j+subtraction[k]] = dp[i][j] + _plus[k]; path[i+1][j+subtraction[k]] = path[i][j];//每次更新都要把path全部复制过来,就是因为这个才用的vector path[i+1][j+subtraction[k]].push_back(k); } } } } for(i = 0; dp[m][fix+i] == -1 && dp[m][fix-i] == -1; i++); int temp = (dp[m][fix+i] > dp[m][fix-i]) ? i : -i; int sumD = ( dp[m][fix+temp] + temp )/2; int sumP = ( dp[m][fix+temp] - temp )/2; printf( "Jury #%d\n", times++ ); printf( "Best jury has value %d for prosecution and value %d for defence:\n", sumD,sumP); for( i=0; i < m; i++ ) printf( " %d", path[m][fix+temp][i]+1); printf( "\n\n" ); } return 0; }
相关文章推荐
- POJ1015-Jury Compromise 以及 uva 323正确二维DP解法
- 【水】uva10003 练手二维DP
- Jury Compromise---poj1015(动态规划,dp,)
- uva 1358 Generator (kmp,dp(高斯消元解法))
- Palindrome Partitioning I,II[leetcode] DFS以及DP的解法
- 选择陪审员 POJ1015 Jury Compromise 动态规划DP 搜索DFS 贪心
- UVA - 323 Jury Compromise——01背包
- UVA 323 Jury Compromise——01背包变形
- UVA 11019 Matrix Matcher( 二维字符匹配 AC自动机 + DP)
- 关于function declared implicitly的正确解法以及extern的用法
- UVa 10285 Longest Run on a Snowboard(DP 二维最长递减子序列)
- uva10313(二维多重DP)
- (DP6.1.4.1)UVA 111 History Grading(最长递增子序列LIS 的LCS 解法)
- UVA - 10003 Cutting Sticks(dp和记忆化搜索两种解法)
- UVA - 11019 Matrix Matcher (AC自动机(二维匹配) + dp)
- UVALive 6257 Chemist's vows --一道题的三种解法(模拟,DFS,DP)
- UVA11775 Unique Story dp+二维树状数组优化
- POJ1015 Jury Compromise——DP——被某些人害苦了!!!
- POJ1609 UVALive2815 UVA1196 ZOJ1787 Tiling Up Blocks【二维最长上升子序列+DP】
- 记忆化搜索,以及其他的dp