bzoj 1021: [SHOI2008]Debt 循环的债务
Posted lxy8584099
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1021: [SHOI2008]Debt 循环的债务相关的知识,希望对你有一定的参考价值。
抓准初始状态 末状态 考虑DP
/************************************************************** Problem: 1021 User: lxy8584099 Language: C++ Result: Accepted Time:600 ms Memory:28440 kb ****************************************************************/ /* 又是DP 多做多看吧。。。 开始分别有sa,sb,sc 价换后分别是 ea,eb,ec 问最小交换几张钱 f[i][a][b] 表示用前i种钱 A目前有a元 B目前有B元(C目前是all-a-b元) 所需要交换钱的最小张数 每次枚举交换之后 A的钱的张数aa B的钱的张数bb 那么交换的张数也能算出来了 */ #include<algorithm> #include<cstdio> #include<cstring> #define min(a,b) ((a>b)?(b):(a)) using namespace std; const int N=1005; int f[7][N][N],inf,mon[7]={0,1,5,10,20,50,100}; int numa[7],numb[7],numc[7],tot[7]; inline int cal(int a,int b,int k){//考虑第k种面额,最后A有a张,B有b张,c有tot-a-b张,需要交换几张达到。 return abs(a-numa[k])+abs(b-numb[k])+abs(tot[k]-a-b-numc[k])>>1; } int main() { int x1,x2,x3,na=0,nb=0,nc=0,n,ea,eb,ec; scanf("%d%d%d",&x1,&x2,&x3); for(int i=6;i>=1;i--) scanf("%d",&numa[i]),na+=mon[i]*numa[i],tot[i]+=numa[i]; for(int i=6;i>=1;i--) scanf("%d",&numb[i]),nb+=mon[i]*numb[i],tot[i]+=numb[i]; for(int i=6;i>=1;i--) scanf("%d",&numc[i]),nc+=mon[i]*numc[i],tot[i]+=numc[i]; n=na+nb+nc; memset(f,0x3f,sizeof(f)); inf=f[0][0][0];f[0][na][nb]=0; ea=na-x1+x3;eb=nb-x2+x1;ec=nc-x3+x2; for(int k=0;k<6;k++) for(int i=0;i<=n;++i) for(int j=0;i+j<=n;++j) { if(f[k][i][j]==inf) continue; // 无法达到这个状态 for(int a=0;a<=tot[k+1];++a) for(int b=0;b+a<=tot[k+1];++b) { int ii=i+mon[k+1]*(a-numa[k+1]); int jj=j+mon[k+1]*(b-numb[k+1]); if(ii>=0&&jj>=0&&ii+jj<=n) f[k+1][ii][jj]=min(f[k+1][ii][jj], f[k][i][j]+cal(a,b,k+1)); } } if(f[6][ea][eb]==inf) puts("impossible"); else printf("%d ",f[6][ea][eb]); return 0; }
以上是关于bzoj 1021: [SHOI2008]Debt 循环的债务的主要内容,如果未能解决你的问题,请参考以下文章
[bzoj1021] [SHOI2008]Debt 循环的债务