# bzoj千题计划111：bzoj1021: [SHOI2008]Debt 循环的债务

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

A->BC   B->AC  C->AB

AB->C  BC->A  AC->B

（C手中即为sum-j-k）

6种情况，枚举给谁多少张 转移即可

ans=min（f[i][ea][eb]）

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

int money[6]={1,5,10,20,50,100};
int a[6],b[6],c[6],tot[6];

int f[7][1001][1001];

{
x=0; int f=1; char c=getchar();
while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
x*=f;
}

int main()
{
//  freopen("bzoj_1021.in","r",stdin);
//    freopen("bzoj_1021.out","w",stdout);
int A,B,C;
int sa=0,sb=0,sc=0;
for(int i=5;i>=0;--i)
{
sa+=a[i]*money[i];
tot[i]+=a[i];
}
for(int i=5;i>=0;--i)
{
sb+=b[i]*money[i];
tot[i]+=b[i];
}
for(int i=5;i>=0;--i)
{
sc+=c[i]*money[i];
tot[i]+=c[i];
}
int ea=sa-A+C,eb=sb-B+A,ec=sc-C+B;
memset(f,127,sizeof(f));
for(int i=0;i<6;++i)
{
f[i][sa][sb]=0;
}
int ans=2e9,sum=ea+eb+ec;
for(int i=0;i<6;++i)
{
for(int j=0;j<=sum;++j)//in A
{
for(int k=0;k+j<=sum;++k) //in B
{
if(f[i][j][k]>2e9) continue;
//A->BC
for(int x=0;x<=a[i];++x)
{
if(x*money[i]>j || x*money[i]+k>sum) break;
for(int y=0;y+x<=a[i];++y)
{
if((x+y)*money[i]>j) break;
if(sum-j-k+y*money[i]>sum) break;
f[i+1][j-(x+y)*money[i]][k+x*money[i]]=min(f[i+1][j-(x+y)*money[i]][k+x*money[i]],f[i][j][k]+x+y);
}
}
//B->AC
for(int x=0;x<=b[i];++x)
{
if(j+x*money[i]>sum || x*money[i]>k) break;
for(int y=0;y+x<=b[i];++y)
{
if((x+y)*money[i]>k) break;
if(sum-j-k+y*money[i]>sum) break;
f[i+1][j+x*money[i]][k-(x+y)*money[i]]=min(f[i+1][j+x*money[i]][k-(x+y)*money[i]],f[i][j][k]+x+y);
}
}
//C->AB
for(int x=0;x<=c[i];++x)
{
if(j+x*money[i]>sum) break;
for(int y=0;y+x<=c[i];++y)
{
if(k+y*money[i]>sum) break;
if(sum-j-k-x*money[i]-y*money[i]<0) break;
f[i+1][j+x*money[i]][k+y*money[i]]=min(f[i+1][j+x*money[i]][k+y*money[i]],f[i][j][k]+x+y);
}
}
//AB->C
for(int x=0;x<=a[i];++x)
{
if(x*money[i]>j) break;
for(int y=0;y<=b[i];++y)
{
if(y*money[i]>k) break;
if(sum-j-k+x*money[i]+y*money[i]>sum) break;
f[i+1][j-x*money[i]][k-y*money[i]]=min(f[i+1][j-x*money[i]][k-y*money[i]],f[i][j][k]+x+y);
}
}
//AC->B
for(int x=0;x<=a[i];++x)
{
if(x*money[i]>j || k+x*money[i]>sum) break;
for(int y=0;y<=c[i];++y)
{
if(k+(x+y)*money[i]>sum) break;
if(sum-j-k-y*money[i]<0) break;
f[i+1][j-x*money[i]][k+(x+y)*money[i]]=min(f[i+1][j-x*money[i]][k+(x+y)*money[i]],f[i][j][k]+x+y);
}
}
//BC->A
for(int x=0;x<=b[i];++x)
{
if(j+x*money[i]>sum || x*money[i]>k) break;
for(int y=0;y<=c[i];++y)
{
if(j+(x+y)*money[i]>sum) break;
if(sum-j-k-y*money[i]<0) break;
f[i+1][j+(x+y)*money[i]][k-x*money[i]]=min(f[i+1][j+(x+y)*money[i]][k-x*money[i]],f[i][j][k]+x+y);
}
}
}
}
ans=min(ans,f[i+1][ea][eb]);
}
if(ans==2e9) printf("impossible");
else cout<<ans;
}

## 1021: [SHOI2008]Debt 循环的债务

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 1116  Solved: 572
[Submit][Status][Discuss]

## Description

Alice、Bob和Cynthia总是为他们之间混乱的债务而烦恼，终于有一天，他们决定坐下来一起解决这个问题。

ice欠Bob 10元，而Cynthia和他俩互不相欠。现在假设Alice只有一张50元，Bob有3张10元和10张1元，Cynthia有3

Bob，而Bob把一张10块给C，此时只有5张钞票被交换过。没过多久他们就发现这是一个很棘手的问题，于是他们找

## Input

输入的第一行包括三个整数：x1、x2、x3（-1,000≤x1，x2，x3≤1,000），其中 x1代表Alice欠Bob的钱（如

a100，a50，a20，a10，a5，a1
b100，b50，b20，b10，b5，b1
c100，c50，c20，c10，c5，c1
a100表示Alice拥有的100元钞票张数，b50表示Bob拥有的50元钞票张数，以此类推。

## Output

如果债务可以还清，则输出需要交换钞票的最少张数；如果不能还清，则输出“impossible”（注意单词全部

10 0 0
0 1 0 0 0 0
0 0 0 3 0 10
0 0 3 0 0 0

-10 -10 -10
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

5

0

## HINT

posted @ 2017-11-22 22:01  TRTTG  阅读(373)  评论(0编辑  收藏  举报