poj 1015 Jury Compromise
2012-07-30 02:25
204 查看
http://poj.org/problem?id=1015
周日,结束了持续两个星期的个人赛,那是多么难以忘怀的一次选拔,成绩可谓差到谷底了...心情也是一样。晚上公布了个人赛的统计结果,庆幸的是训练依然继续,但是将会和谁组队,就只好看明天下午有哪位大牛会好心收留我了。恶心的结果,也是意料之内的...心情再怎么不好,还是应该为能够继续训练偷笑一下,缓解这一个星期的郁闷!
在个人赛中,出现很多种类型的题目....什么网络流,二分匹配,凸包,线段树(我打算在未来几天里将我前几天弄懂的线段树写一下),生成树计数...甚至出现了随机算法 快速分解质因数 (链接里是一个比较简明的Pollard-rho算法代码)。
晚上回到宿舍,在poj和hdu找了些dp的题目练了一下,这是其中一题。题意可以理解为,给出n种物品,求取其中m种,使得这m种物品的分别两种属性的和的差距(和的绝对值)最小。如果有多种情况,输出和最大的一种,并且要输出选择的物品的编号。
一开始用物品的两种属性进行dp,用boolean数组来判断能达到的位置,可是这时的时间复杂度是O(n*m*maxsum^2),刚开始算错数了,没发觉这个问题..交上去果断返回一个TLE。于是,我构思了一下,更改了dp的状态。因为想到,直接记录他们的差和和就可以推出原来的两个数。两者的差不取绝对值,因此有可能是负数,所以要进行数组的平移,最后构造出类似天平的一个结构。
dp的几个状态:
第一个状态——当前决策第i个物品(如果不是要backtrack出所用的物品,这个状态无需表达出来,可以直接用滚动数组实现)
第二个状态——当前选择了j个物品
第三个状态——选择j件物品后,两种属性的差值是k
dif —— 第一种属性减第二种的差值
sum —— 两种属性的和
状态转移方程是 dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - 1][k - dif] + sum)
代码:(两部分都贴出来,用宏做开关....另外,我把debug也放进去了,所以看起来会比较长)
View Code
Work Harder!Work for My Better Life!
--Written by Lyon
周日,结束了持续两个星期的个人赛,那是多么难以忘怀的一次选拔,成绩可谓差到谷底了...心情也是一样。晚上公布了个人赛的统计结果,庆幸的是训练依然继续,但是将会和谁组队,就只好看明天下午有哪位大牛会好心收留我了。恶心的结果,也是意料之内的...心情再怎么不好,还是应该为能够继续训练偷笑一下,缓解这一个星期的郁闷!
在个人赛中,出现很多种类型的题目....什么网络流,二分匹配,凸包,线段树(我打算在未来几天里将我前几天弄懂的线段树写一下),生成树计数...甚至出现了随机算法 快速分解质因数 (链接里是一个比较简明的Pollard-rho算法代码)。
晚上回到宿舍,在poj和hdu找了些dp的题目练了一下,这是其中一题。题意可以理解为,给出n种物品,求取其中m种,使得这m种物品的分别两种属性的和的差距(和的绝对值)最小。如果有多种情况,输出和最大的一种,并且要输出选择的物品的编号。
一开始用物品的两种属性进行dp,用boolean数组来判断能达到的位置,可是这时的时间复杂度是O(n*m*maxsum^2),刚开始算错数了,没发觉这个问题..交上去果断返回一个TLE。于是,我构思了一下,更改了dp的状态。因为想到,直接记录他们的差和和就可以推出原来的两个数。两者的差不取绝对值,因此有可能是负数,所以要进行数组的平移,最后构造出类似天平的一个结构。
dp的几个状态:
第一个状态——当前决策第i个物品(如果不是要backtrack出所用的物品,这个状态无需表达出来,可以直接用滚动数组实现)
第二个状态——当前选择了j个物品
第三个状态——选择j件物品后,两种属性的差值是k
dif —— 第一种属性减第二种的差值
sum —— 两种属性的和
状态转移方程是 dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - 1][k - dif] + sum)
代码:(两部分都贴出来,用宏做开关....另外,我把debug也放进去了,所以看起来会比较长)
View Code
#include <cstdio> #include <cstring> #include <cmath> #define debug 0 #define prog 1//1是较高效的代码 2是超时的代码 int min2(int _a, int _b){return _a < _b ? _a : _b;} int max2(int _a, int _b){return _a > _b ? _a : _b;} int s[20], top; int d[201], p[201]; #if prog == 1 int dp[201][21][1001]; const int inf = 100000000; const int mid = 500;//这里至少要420,这样下面的代码就不需要分类讨论了 int main(){ int n, m; int c = 1; while (~scanf("%d%d", &n, &m) && (n || m)){ for (int k = 0; k <= n; k++){ for (int i = 0; i <= m; i++){ for (int j = 0, endj = mid << 1; j <= endj; j++){ dp[k][i][j] = -inf; } } dp[k][0][mid] = 0; } for (int i = 1; i <= n; i++){ scanf("%d%d", &d[i], &p[i]); for (int j = 1, endj = min2(i, m); j <= endj; j++){ int dif = d[i] - p[i]; int sum = d[i] + p[i]; for (int k = mid - 400, endk = mid + 400; k <= endk; k++){ dp[i][j][k] = max2(dp[i - 1][j][k], dp[i - 1][j - 1][k - dif] + sum); } } } bool found = false; int mi = 0, mj = 0; for (int i = 0; i <= 400 && !found; i++){ if (dp [m][mid + i] > 0){ found = true; mj = i; mi = dp [m][mid + i]; } if (dp [m][mid - i] > 0){ found = true; if (mi < dp [m][mid - i]){ mj = -i; mi = dp [m][mid - i]; } } } #if debug for (int i = 0; i <= m; i++){ for (int j = mid - 5; j <= mid + 5; j++){ printf("%d ", dp [i][j]); } puts(""); } printf("mi %d mj %d\n", mi, mj); puts(""); printf("%d %d\n", (mi + mj) >> 1, (mi - mj) >> 1); #endif printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n", c, (mi + mj) >> 1, (mi - mj) >> 1); int t = n; top = 0; mj += mid; for (; t && mj && m; t--){//刚开始m忘记判断了,所以RE了几次,还以为是数组不够大搞到我不停开大数组 int dif = d[t] - p[t]; int sum = d[t] + p[t]; if (dp[t][m][mj] == dp[t - 1][m - 1][mj - dif] + sum){ #if debug puts("pass"); #endif m--; mj -= dif; s[top++] = t; } }//backtrack只要直接找到满足更新条件的两个数就可以了 c++; for (int i = top - 1; i >= 0; i--){ printf(" %d", s[i]); } puts(""); puts(""); } return 0; } #endif #if prog == 2 bool dp[21][401][401]; int main(){ int n, m; int c = 1; int sumd, sump; while (~scanf("%d%d", &n, &m) && (n || m)){ memset(dp, 0, sizeof(dp)); dp[0][0][0] = true; sumd = sump = 0; for (int i = 1; i <= n; i++){ scanf("%d%d", &d[i], &p[i]); sumd += d[i]; sumd = min2(sumd, 400); sump += p[i]; sump = min2(sump, 400); for (int l = min2(i, m); l >= 1; l--){ for (int j = sumd; j >= d[i]; j--){ for (int k = sump; k >= p[i]; k--){ dp[l][j][k] |= dp[l - 1][j - d[i]][k - p[i]]; } } } } bool found = false; int mi = 0, mj = 0; for (int t = 0; t <= 400 && !found; t++){ for (int i = 400; i >= t && !found; i--){ if (dp[m][i][i - t]){ found = true; mi = i; mj = i - t; } else if (dp[m][i - t][i]){ found = true; mi = i - t; mj = i; } } } #if debug for (int i = 0; i <= 20; i++){ for (int j = 0; j <= 20; j++){ printf("%d", dp[1][i][j]); } puts(""); } printf("i %d j %d\n", mi, mj); #endif printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n", c, mi, mj); c++; top = 0; while (mi && mj && m){ for (int i = n; i >= 1; i--){ if (mi - d[i] >= 0 && mj - p[i] >= 0 && dp[m - 1][mi - d[i]][mj - p[i]]){ s[top++] = i; mi -= d[i]; mj -= p[i]; m--; } } } for (int i = top - 1; i >= 0; i--){ printf(" %d", s[i]); } puts(""); } return 0; } #endif
Work Harder!Work for My Better Life!
--Written by Lyon
相关文章推荐
- POJ_1015_Jury Compromise
- POJ 1015 Jury Compromise(双塔DP)
- Jury Compromise(poj 1015)
- poj 1015 Jury Compromise
- POJ 1015 Jury Compromise(DP)
- poj 1015 Jury Compromise
- POJ 1015 Jury Compromise(DP+回溯)
- poj - 1015 - Jury Compromise(dp)
- 【dp】POJ 1015 Jury Compromise
- poj 1015 Jury Compromise(DP)
- poj 1015 Jury Compromise 动态规划
- POJ 1015 Jury Compromise
- POJ 1015 Jury Compromise
- POJ 1015: Jury Compromise
- poj 1015 Jury Compromise 01背包+输出方案
- poj 1015 Jury Compromise
- poj 1015 Jury Compromise
- [POJ 1015] Jury Compromise
- POJ1015-Jury Compromise-dp
- POJ 1015 Jury Compromise【DP】