您的位置:首页 > 其它

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

2018-02-25 18:49 183 查看
【题目链接】

  http://www.lydsy.com/JudgeOnline/problem.php?id=1021

【题解】

  记 f[i][j][k] 表示考虑到第 i 中面额的钞票,A当前盈利了 j 元,B当前盈利了 k 元,最少盈利的钱数。

  转移是,在第 i 轮中,枚举A付出了 i1 张该面额钞票,B付出了 i2 张该面额的钞票。

  时间复杂度 O(10002∗6∗30210002∗6∗302) 实际远远不到。

  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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: