去膜拜题解了>_>玛雅原来是动规……
让我先理解一下为什么要用动规:这个题根据钱数推方案其实是无从下手的……(线性规划?……事实证明我想多了)
啦~我们先来看个超级简化版的问题:怎么判无法还清?正着判很麻烦对不对= =(其实是我没想……)
那么我们倒着来考虑:有哪些状态是我们通过交换钱币能够到达的,这个可以递推对不>_>
现在我们就知道哪些状态我们是可以到达的了……再多想一下……递推……如果我们依次考虑每种面额的交换策略,顺便也就知道了我们到达这个状态的最小交换次数对吧?
原因:因为每种面值只有6种策略(给出钱的是一个人,3种,给出钱的是两个人,3种),且不同面值之间的交换互不影响(这不是废话吗!我手里有多少张10块的难道还会影响我手里100块的张数?可是我一开始绕进这个弯里没走出来TAT)
(P.S.看到这里你就可以去写题了,因为我动规方程比较奇葩……自己想的时候又把自己坑了
我是让$f[i][j][k]$表示当前a手里有 j 块钱,b手里有 k 块钱,现在该考虑第 i 种面额的钞票(但是还没有对第 i 种钞票进行分配!!我忘了啊啊啊!!!看了题解以后跟人家的方法搞混了?>_>)
那么我是分3种情况讨论的(将上面的6种情况组合了一下)……1. a给b、c或是b、c给a ; 2.b给a、c或是a、c给b;3.c给a、b或是a、b给c。
明显可行的状态比数组大小小得多,所以就用了队列来保存/扩展可行状态(类似记忆化搜索的策略吧)
(不过我这种姿势明显是比较捉急的……不过也能过>_>想看 快/短 一点的做法请戳@regina8023 @rausen)
自我感觉我写这题的动规的姿势还是蛮特别的,而且还是第666个提交 2333~沾沾自喜一下(>_<)~
1 /************************************************************** 2 Problem: 1021 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:784 ms 7 Memory:52136 kb 8 ****************************************************************/ 9 10 //BZOJ 1021 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int M=1e6+10,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 const int money[8]={0,1,5,10,20,50,100}; 32 int a[8],b[8],c[8],sa,sb,sc,ea,eb,ec; 33 int n,m,f[8][1001][1001],tot; 34 bool inq[8][1001][1001]; 35 struct node{ 36 int x,y,z; 37 }Q[M]; 38 void dp(){ 39 F(i,1,7) F(j,0,tot) F(k,0,tot) f[i][j][k]=INF; 40 int l=0,r=-1; 41 Q[++r]=(node){1,sa,sb}; f[1][sa][sb]=0; inq[1][sa][sb]=1; 42 while(l<=r){ 43 node now=Q[l++]; 44 int x=now.x,y=now.y,z=now.z; 45 inq[x][y][z]=0; 46 if (x==7) continue; 47 if (f[x+1][y][z]>f[x][y][z]){ 48 f[x+1][y][z]=f[x][y][z]; 49 if (!inq[x+1][y][z]){ 50 Q[++r]=(node){x+1,y,z}; 51 inq[x+1][y][z]=1; 52 } 53 } 54 F(i,-b[x],a[x]) F(j,-c[x],a[x]-i){ 55 int ty=y-(i+j)*money[x],tz=z+i*money[x]; 56 if (ty<0) break; 57 if (f[x+1][ty][tz]>f[x][y][z]+abs(i)+abs(j)){ 58 f[x+1][ty][tz]=f[x][y][z]+abs(i)+abs(j); 59 if (!inq[x+1][ty][tz]){ 60 Q[++r]=(node){x+1,ty,tz}; 61 inq[x+1][ty][tz]=1; 62 } 63 } 64 } 65 F(i,-a[x],b[x]) F(j,-c[x],b[x]-i){ 66 int ty=y+i*money[x],tz=z-(i+j)*money[x]; 67 if (tz<0) break; 68 if (f[x+1][ty][tz]>f[x][y][z]+abs(i)+abs(j)){ 69 f[x+1][ty][tz]=f[x][y][z]+abs(i)+abs(j); 70 if (!inq[x+1][ty][tz]){ 71 Q[++r]=(node){x+1,ty,tz}; 72 inq[x+1][ty][tz]=1; 73 } 74 } 75 } 76 F(i,-a[x],c[x]) F(j,-b[x],c[x]-i){ 77 int ty=y+i*money[x],tz=z+j*money[x]; 78 if (ty+tz>tot) break; 79 if (f[x+1][ty][tz]>f[x][y][z]+abs(i)+abs(j)){ 80 f[x+1][ty][tz]=f[x][y][z]+abs(i)+abs(j); 81 if (!inq[x+1][ty][tz]){ 82 Q[++r]=(node){x+1,ty,tz}; 83 inq[x+1][ty][tz]=1; 84 } 85 } 86 } 87 } 88 // F(i,1,7) F(j,0,tot) F(k,0,tot) 89 // if (f[i][j][k]!=INF)printf("f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k]); 90 if (f[7][ea][eb]==INF||ea<0||eb<0||ec<0||ea+eb+ec>tot) puts("impossible"); 91 else printf("%d\n",f[7][ea][eb]); 92 } 93 94 95 int main(){ 96 #ifndef ONLINE_JUDGE 97 freopen("1021.in","r",stdin); 98 freopen("1021.out","w",stdout); 99 #endif 100 int x1=getint(),x2=getint(),x3=getint(); 101 F(i,1,6) {a[7-i]=getint();sa+=a[7-i]*money[7-i];} 102 F(i,1,6) {b[7-i]=getint();sb+=b[7-i]*money[7-i];} 103 F(i,1,6) {c[7-i]=getint();sc+=c[7-i]*money[7-i];} 104 tot=sa+sb+sc; 105 ea=sa-x1+x3; eb=sb-x2+x1; ec=sc-x3+x2; 106 dp(); 107 return 0; 108 }