BZOJ 1021 循环的债务
逐面值考虑
令各个人拥有的Money为状态
已知初状态和目标状态
DP出各种状态
类似于\(POJ\ 1837\)
#include <iostream>
using namespace std;
const int INF=1034567890;
const int Lim=1000000000;
int x1, x2, x3;
int M=1000;
int A=0, B=0, C=0;
int aimA, aimB, aimC;
int Am[7], Bm[7], Cm[7], Tot[7];
int Val[7]={0, 1, 5, 10, 20, 50, 100};
int F[7][1111][1111];
int abs(int a){
return (a<0)?(-a):a;
}
int dis(int a, int b, int at){
return (abs(a-Am[at])+abs(b-Bm[at])+abs(Tot[at]-a-b-Cm[at]))/2;
}
int main(){
ios_base::sync_with_stdio(false);
cin >> x1 >> x2 >> x3;
for(int i=6;i>=1;--i) cin >> Am[i], Tot[i]+=Am[i];
for(int i=1;i<=6;++i) A+=Am[i]*Val[i];
aimA=A-x1+x3;
for(int i=6;i>=1;--i) cin >> Bm[i], Tot[i]+=Bm[i];
for(int i=1;i<=6;++i) B+=Bm[i]*Val[i];
aimB=B+x1-x2;
for(int i=6;i>=1;--i) cin >> Cm[i], Tot[i]+=Cm[i];
for(int i=1;i<=6;++i) C+=Cm[i]*Val[i];
aimC=C-x3+x2;
M=A+B+C;
for(int i=0;i<7;++i)
for(int j=0;j<1111;++j)
for(int k=0;k<1111;++k) F[i][j][k]=INF;
F[0][A][B]=0;
for(int i=0;i<6;++i)
for(int j=0, jj;j<=M;++j)
for(int k=0, kk;k+j<=M;++k){
if(F[i][j][k]>Lim) continue;
for(int a=0;a<=Tot[i+1];++a)
for(int b=0;a+b<=Tot[i+1];++b){
jj=j+Val[i+1]*(a-Am[i+1]);
kk=k+Val[i+1]*(b-Bm[i+1]);
if(jj>=0 && kk>=0 && jj+kk<=M)
F[i+1][jj][kk]=min(F[i+1][jj][kk], F[i][j][k]+dis(a, b, i+1));
}
}
if(F[6][aimA][aimB]<=Lim) cout << F[6][aimA][aimB] << endl;
else cout << "impossible" << endl;
return 0;
}
/*
10 0 0
0 1 0 0 0 0
0 0 0 3 0 10
0 0 3 0 0 0
5
*/
/*
-10 -10 -10
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0
*/