1. 程式人生 > >bzoj 1021: [SHOI2008]Debt 迴圈的債務

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\n",f[6][ea][eb]);     return 0; }