真是蒟蒻,已经连续几题沦落到不看题解写不出的地步了,最近不太想写题了,学习新的算法吧
用f[i][j][k]表示算到第i种钱,乙有j元,丙有k元的最小方案数,记录可以转移的方案以及去掉不可以转移的方案就行了
CODE:
#include<cstdio>
#include<iostream>#include<cstring>#include<algorithm>using namespace std;int f[7][1010][1010],t[4][7],sum[4];int a[7]={0,1,5,10,20,50,100};int x[4];int c[4];struct node{ int x,y;}q[101000],k[101000];bool b[7][1010][1010];int check(int x,int y,int z,int ans){ if (b[x][y][z]) { f[x][y][z]=min(f[x][y][z],ans); return 0; }else { b[x][y][z]=1; f[x][y][z]=ans; } if (x==6) return 0; if (x!=3){ if (abs(sum[2]-y)%a[x+1]!=0) return 0; if (abs(sum[3]-z)%a[x+1]!=0) return 0; if (abs(sum[2]+sum[3]-y-z)%a[x+1]!=0) return 0; } k[0].x++;k[k[0].x]=(node){y,z}; return 0;}int solve(int i,int j,int x,int y,int z){ for (int k=0;k<=t[y][i];k++) for (int l=0;l<=t[z][i];l++) { c[x]=k+l;c[y]=-k;c[z]=-l; check(i,q[j].x+c[2]*a[i],q[j].y+c[3]*a[i],f[i-1][q[j].x][q[j].y]+k+l); } for (int k=0;k<=t[x][i];k++) for (int l=0;l+k<=t[x][i];l++){ c[x]=-(k+l);c[y]=k;c[z]=l; check(i,q[j].x+c[2]*a[i],q[j].y+c[3]*a[i],f[i-1][q[j].x][q[j].y]+k+l); } return 0;}int main(){ scanf("%d%d%d",&x[1],&x[2],&x[3]); for (int i=1;i<=3;i++) for (int j=1;j<=6;j++) { scanf("%d",&t[i][6-j+1]); sum[i]+=t[i][6-j+1]*a[6-j+1]; } q[0].x=1; q[1]=(node){sum[2],sum[3]}; sum[2]+=x[1]-x[2]; sum[1]+=x[3]-x[1]; sum[3]+=x[2]-x[3]; for (int i=1;i<=6;i++){ k[0].x=0; for (int j=1;j<=q[0].x;j++) { solve(i,j,1,2,3); solve(i,j,2,1,3); solve(i,j,3,1,2); } swap(k,q); } if (b[6][sum[2]][sum[3]]) printf("%d",f[6][sum[2]][sum[3]]); else printf("impossible"); return 0;}