[bzoj1021][SHOI2008]Debt 循环的债务【dp】

【题目链接】
  http://www.lydsy.com/JudgeOnline/problem.php?id=1021
【题解】
  记 f[i][j][k] 表示考虑到第 i 中面额的钞票,A当前盈利了 j 元,B当前盈利了 k 元,最少盈利的钱数。
  转移是,在第 i 轮中,枚举A付出了 i1 张该面额钞票,B付出了 i2 张该面额的钞票。
  时间复杂度 O(100026302) 实际远远不到。
  tips:从小的往大的搜,这样比较多的一开始就搜完了,比较优。
  

/* --------------
    user Vanisher
    problem bzoj-1021 
----------------*/
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    T       1000
# define    N       2050
using namespace std;
int read(){
    int tmp=0, fh=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    return tmp*fh;
}

const int p[7]={0,100,50,20,10,5,1};
short int f[7][N][N];
int num1[2][N*N],num2[2][N*N],r[4],h[4][7],sum[7],pr[2];
bool mp[7][N][N];
int main(){
    int a=read(), b=read(), c=read();
    r[1]=c-a, r[2]=a-b, r[3]=b-c;
    if (r[1]>T||r[2]>T||-r[1]>T||-r[2]>T){
        printf("impossible\n");
        return 0;
    }
    for (int i=1; i<=3; i++)
        for (int j=1; j<=6; j++)
            h[i][7-j]=read(), sum[7-j]+=h[i][7-j];
    memset(f,inf,sizeof(f));
    int f1=0, f2=1;
    short int ans=inf%65536;
    f[0][T][T]=0; pr[f1]=1; num1[f1][1]=T; num2[f1][1]=T; 
    for (int i=1; i<=6; i++){
        for (int i1=-h[1][i]; i1<=sum[i]-h[1][i]; i1++)
            for (int i2=-h[2][i]; i2<=sum[i]-h[2][i]; i2++){
                if (i1+i2>h[3][i]) continue;
                for (int j=1; j<=pr[f1]; j++){
                    int now1=num1[f1][j]+p[7-i]*i1,
                        now2=num2[f1][j]+p[7-i]*i2;
                    f[i][now1][now2]=min((int)f[i][now1][now2],f[i-1][num1[f1][j]][num2[f1][j]]+max(max(abs(i1+i2),abs(i1)),abs(i2)));
                    if (f[i][now1][now2]<ans&&mp[i][now1][now2]==false){
                        mp[i][now1][now2]=true;
                        num1[f2][++pr[f2]]=now1, num2[f2][pr[f2]]=now2;
                    }
                }
            }
        swap(f1,f2);
        pr[f2]=0;
        ans=min(ans,f[i][r[1]+T][r[2]+T]);
    }
    if (ans==inf%65536)
        printf("impossible\n");
        else printf("%hd\n",ans);   
    return 0;
}
posted @ 2018-02-25 18:50  Vanisher  阅读(104)  评论(0编辑  收藏  举报