循环的债务[恶心的DP]

传送门

f[i][v1][v2] 表示到第i种钱币 , 第一个人剩多少 , 第二个人剩多少 , 第三个人减一下就出来了

num[i][j] 表示第i个人的第j种前有多少张

val[i] 表示第i种钱的价值

f[i][v1][v2]=min(f[i][v1][v2],f[i-1][j][k]+w)

其中 v1 = j+(num[1][i]-x1)*val[i] ;

v2=k+(num[2][i]-x2)*val[i]

w = [abs(Num[1][i] - x1) + abs(Num[2][i] - x2) + abs(Num[3][i] - x3)]/2

 我们枚举x1 , y1,如果合法就转移


#include<bits/stdc++.h>
#define N 1050
#define M 10
using namespace std;
int X1,X2,X3,tot,cnt[M],Sum[N];
int Num[M][M],val[M]={0,100,50,20,10,5,1};
int f[M][N][N],inf,ans;
int main(){
	scanf("%d%d%d",&X1,&X2,&X3);
	for(int i=1;i<=3;i++){
		for(int j=1;j<=6;j++){
			scanf("%d",&Num[i][j]);
			Sum[i] += Num[i][j] * val[j];
			tot += Num[i][j] * val[j];
			cnt[j] += Num[i][j];
		}
	}
	memset(f,127,sizeof(f)); 
	f[0][Sum[1]][Sum[2]] = 0; inf = ans = f[1][1][1]; 
	for(int i=1;i<=6;i++) for(int j=0;j<=tot;j++) for(int k=0;k+j<=tot;k++)
		if(f[i-1][j][k]!=inf) {for(int x1=0;x1<=cnt[i];x1++) 
			for(int x2=0;x1+x2<=cnt[i];x2++){
				int now1 = j - (Num[1][i] - x1) * val[i];
				int now2 = k - (Num[2][i] - x2) * val[i];
				int x3 = cnt[i] - x1 - x2;
				if(now1 >= 0 && now2 >= 0 && now1 + now2 <= tot){
					int w = abs(Num[1][i] - x1) + abs(Num[2][i] - x2) + abs(Num[3][i] - x3);
					f[i][now1][now2] = min(f[i][now1][now2] , f[i-1][j][k] + (w>>1)); 
				}
			}		
		}
	int S1 = Sum[1] - X1 + X3 , S2 = Sum[2] - X2 + X1 , S3 = Sum[3] - X3 + X2; 
	for(int i=0;i<=6;i++) ans = min(ans , f[i][S1][S2]);
	if(S1<0 || S2<0 || S3<0 || ans == inf) printf("impossible");
	else printf("%d",ans); return 0;
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/84490308