http://poj.org/problem?id=1015
题意: 两个数x, y初始是0, 共有n个操作, 每个操作向x加a, y加b, 要求选出恰好m次操作, 使得x和y的差最小, 在此基础上, 令x+y最大, 输出最终x和y的值, 并按升序输出都取了那几个位置的数.
思路:双塔dp, dp[i][j]中i表示已经取了i个数, j表示x和y当前的差是多少.
所以, 枚举取了几个数→枚举差值→枚举下一个选的数.
注意:
1: 差值可能是负的, 要加一个数(fix)将范围移动到0~x之间.
2: 初始化dp数组要为-1, 表示当前此状态不可达, 否则(赋0的话)会出现"本来这个状态到不了, 却被当作值为0的可达状态"的情况.
3: 用dp[i-1][j]+a+b更新dp[i][j+a-b] 和 用dp[i-1][j-(a-b)]+a+b更新dp[i][j] 是不同的:
后者是我的代码, 要注意控制j>a-b&&j-a+b<=fix*2(显然fix*2是能达到的最高值了, 再高没有意义,那些状态不可能达到, 自然也没有子状态, 我空间开小了, 又没有加限定条件, 开了805访问到820了)
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<iostream>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=205;
const int inf=1e9+7;
int n,m;
int dp[205][805];
int path[205][805];
struct node {
int a,b;
} pep[M];
int fix;
bool hv_used(int i,int j,int k) {
while(1) {
if(i==0)
return 0;
if(path[i][j]==k)
return 1;
j-=pep[ path[i][j] ].a-pep[ path[i][j] ].b;
i--;
}
}
void output() {
int pos;
for(int i=0; i<=fix; i++) {
if(dp[m][fix+i]>=0&&dp[m][fix+i]>=dp[m][fix-i]) {
pos=fix+i;
break;
}
if(dp[m][fix-i]>=0&&dp[m][fix-i]>=dp[m][fix+i]) {
pos=fix-i;
break;
}
}
printf("Best jury has value %d for prosecution and value %d for defence:\n"
,(dp[m][pos]+pos-fix)/2,(dp[m][pos]-pos+fix)/2);
vector<int>s;
int ii=m,jj=pos;
while(1) {
if(ii==0)
break;
s.push_back(path[ii][jj]);
jj-=pep[ path[ii][jj] ].a-pep[ path[ii][jj] ].b;
ii--;
}
sort(s.begin(),s.end());
for(int i=0; i<s.size(); i++) {
printf(" %d",s[i]);
}
printf(" ");
puts("");
puts("");
}
int main() {
int caz=0;
while(~scanf("%d%d",&n,&m)&&(n||m)) {
caz++;
for(int i=1; i<=n; i++) {
scanf("%d%d",&pep[i].a,&pep[i].b);
}
printf("Jury #%d\n",caz);
fix=m*20;
memset(dp,-1,sizeof(dp));
memset(path,0,sizeof(path));
dp[0][fix]=0;
for(int i=1; i<=m; i++) {
for(int j=0; j<=2*fix; j++) {
for(int k=1; k<=n; k++) {
int a=pep[k].a,b=pep[k].b;
if(j>=a-b&&j-a+b<=2*fix
&&dp[i-1][j-(a-b)]>=0//这里最高会访问j-(a-b)=820位置的数据,所以不能开805
&&dp[i][j]<=dp[i-1][j-(a-b)]+a+b
&&hv_used(i-1,j-(a-b),k)==0) {
dp[i][j]=dp[i-1][j-(a-b)]+a+b;
path[i][j]=k;
}
}
}
}
output();
}
return 0;
}
/*
21 13
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
20 20
*/