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

*/
posted @ 2018-03-28 13:44  Pickupwin  阅读(147)  评论(0编辑  收藏  举报