您的位置:首页 > 其它

POJ-1015(离散化DP)

2014-06-29 22:54 239 查看
题目要求|D(J)-P(J)|最小,但|D(J)-P(J)|显然不符合最优子结构,不能直接动态规划,但题目中说要使|D(J)-P(J)|最小时的D(J)+P(J)最大化,我们知道D(J)+P(J)是符合最优子结构的,要是只用让D(J)+P(J)最大,那就是一个0-1背包问题了,想着要是能将D(J)-P(J)作为一个维度,有一定的范围,再对D(J)+P(J)动态规划的话就好了:

令f(i,j,k)表示在前i个人中选取k个人,且这k个人组成的Jury满足|D(J)-P(J)|=k,这个状态下的最大D(J)+P(J),遍历之后,再对|k| = 0~400遍历f(n,m,k),得到第一个有效的f(n,m,k)就是我们要找的k了

实现时参考了这篇文章:http://hi.baidu.com/yzwlovezxh/item/9235212c03b2dfcea5275a44



#include <cstdio>
inline int max(int a, int b){ return a > b ? a : b; }
inline int min(int a, int b){ return a < b ? a : b; }

int N, M;
int v[201][2];
/* mirror D(J)-P(J)'s range [-400,400] to [0, 800] */
int  f[21][201][400 + 400 + 1];
bool p[21][201][400 + 400 + 1];

void print(int i, int j, int k)
{
if(i == 0 || j == 0) return;
if(p[i][j][k]){
print(i-1, j-1, k - (v[j][0] - v[j][1]));
//        printf("%d is choosen when we choose %d people from %d candidates with D(J)-P(J) = %d\n",
//               j, i, j, k - 400);
printf(" %d", j);
}
else print(i, j-1, k);
}
void solve()
{
//initialize
int mag = M * 20;
for(int i = 0; i <= M; ++i)
for(int j = i; j <= N; ++j)
for(int k = 400 - mag; k <= 400 + mag; ++k)
f[i][j][k] = -1;
for(int j = 0; j <= N; ++j) f[0][j][400] = 0;
//dp
for(int i = 1; i <= M; ++i){//we want to choose i people jury
for(int j = i; j <= N; ++j){//choose i people from first j guys
int dif = v[j][0] - v[j][1];//di - pi
int sum = v[j][0] + v[j][1];//di + pi
int high = min(400 + mag, 400 + mag + dif);
int low = max(400 - mag, 400 - mag + dif);
for(int k = low; k <= high; ++k){
if(j > i){
f[i][j][k] = f[i][j-1][k];//not choose j
p[i][j][k] = false;
}
if(f[i-1][j-1][k-dif] != -1 &&
f[i][j][k] < f[i-1][j-1][k-dif] + sum){//try to choose j
f[i][j][k] = f[i-1][j-1][k-dif] + sum;
p[i][j][k] = true;
//                    printf("updated by f[%d][%d][%d] = %d, ", i-1, j-1, k-dif-400, f[i-1][j-1][k-dif]);
}
//                printf("f[%d][%d][%d] = %d\n", i, j, k-400, f[i][j][k]);
}
}
}
//get path
for(int d = 0; d <= mag; ++d){
//        printf("f[%d][%d][%d] = %d\n", M, N, d, f
[M][d]);
if(f[M]
[400 + d] > f[M]
[400 - d]){
//            printf("best jury has dif = %d, sum = %d\n", d, f[M]
[400 + d]);
printf("Best jury has value %d for prosecution and value %d for defence:\n",
(f[M]
[400 + d] - d)/2, (f[M]
[400 + d] + d)/2);
print(M, N, 400 + d);
break;
}
else if(f[M]
[400 - d] != -1){
//           printf("best jury has dif = %d, sum = %d\n", d, f[M]
[400 - d]);
printf("Best jury has value %d for prosecution and value %d for defence:\n",
(f[M]
[400 - d] + d)/2, (f[M]
[400 - d] - d)/2);
print(M, N, 400 - d);
break;
}
}
}

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
int t = 0;
while(scanf("%d%d", &N, &M), N || M){
++t;
printf("Jury #%d\n", t);
for(int i = 1; i <= N; ++i) scanf("%d%d", &v[i][1], &v[i][0]);//pi, di
solve();
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: