转载:http://www.cnblogs.com/Asm-Definer/p/4372749.html

1021: [SHOI2008]Debt 循环的债务

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 985  Solved: 513
[Submit][Status][Discuss]

Description

  Alice、Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题。
不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在清还债务的时候尽可能少的交换现金。比如说,Al
ice欠Bob 10元,而Cynthia和他俩互不相欠。现在假设Alice只有一张50元,Bob有3张10元和10张1元,Cynthia有3
张20元。一种比较直接的做法是:Alice将50元交给Bob,而Bob将他身上的钱找给Alice,这样一共就会有14张钞票
被交换。但这不是最好的做法,最好的做法是:Alice把50块给Cynthia,Cynthia再把两张20给Alice,另一张20给
Bob,而Bob把一张10块给C,此时只有5张钞票被交换过。没过多久他们就发现这是一个很棘手的问题,于是他们找
到了精通数学的你为他们解决这个难题。

Input

  输入的第一行包括三个整数:x1、x2、x3(-1,000≤x1,x2,x3≤1,000),其中 x1代表Alice欠Bob的钱(如
果x1是负数,说明Bob欠了Alice的钱) x2代表Bob欠Cynthia的钱(如果x2是负数,说明Cynthia欠了Bob的钱) x3
代表Cynthia欠Alice的钱(如果x3是负数,说明Alice欠了Cynthia的钱)
接下来有三行
每行包括6个自然数:
a100,a50,a20,a10,a5,a1
b100,b50,b20,b10,b5,b1
c100,c50,c20,c10,c5,c1
a100表示Alice拥有的100元钞票张数,b50表示Bob拥有的50元钞票张数,以此类推。
另外,我们保证有a10+a5+a1≤30,b10+b5+b1≤30,c10+c5+c1≤30,而且三人总共拥有的钞票面值总额不会
超过1,000。

Output

  如果债务可以还清,则输出需要交换钞票的最少张数;如果不能还清,则输出“impossible”(注意单词全部
小写,输出到文件时不要加引号)。

Sample Input

输入一
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

Sample Output

输出一
5
输出二
0
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=,INF=0x3f3f3f3f,val[]={,,,,,};
int cnt[][],tot[],Cur[],Tar[],Sum,f[][maxn][maxn];//f开三维,第一位滚动数组用,第二第三维则是A,B所拥有的钱的数目,因为A,B确定,C一定确定,所以不需要开第四维
inline void init(){
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    for(int i=;i<;++i) for(int j=;j>=;--j){
        scanf("%d",&cnt[i][j]);
        Cur[i]+=cnt[i][j]*val[j];
        tot[j]+=cnt[i][j];
    }
    Sum=Cur[]+Cur[]+Cur[];
    Tar[]=Cur[]-a+c;//A的目标钱数
    Tar[]=Cur[]-b+a;//B的目标钱数
    if(Tar[]<||Tar[]<||Sum-Tar[]-Tar[]<) {
        puts("impossible");
        exit();
    }
}
int main(){
    init();
    const int rang=Sum+;
    int i,j,k,a,b,t,tmp,da,db,cnta,cntb;
    bool cur,las;
    for(i=;i<=Sum;++i)
        memset(f[][i],0x3f,sizeof(int)*rang);
    f[][Cur[]][Cur[]]=;
    for(i=;i<;++i) {
        cur=i&,las=cur^;
        for(j=;j<=Sum;++j) memset(f[cur][j],0x3f,sizeof(int)*rang);
        for(j=;j<=Sum;++j){//这里枚举的方向无所谓
            t=Sum-j;
            for(k=;k<=t;++k) {
                if(f[las][j][k]==INF) continue;
                f[cur][j][k]=min(f[cur][j][k],f[las][j][k]);
                for(a=;a<=tot[i];++a) {//枚举第i种钱的数目在A中的个数
                    tmp=tot[i]-a;
                    for(b=;b<=tmp;++b){//枚举第i种钱的数目在B中的个数
                        da=a-cnt[][i],db=b-cnt[][i];//da是交换时A所用的第i种钱的数目,db是B所用的。。
                        cnta=j+da*val[i],cntb=k+db*val[i];
                        if(cnta<||cntb<) continue;
                        f[cur][cnta][cntb]=min(f[cur][cnta][cntb],f[las][j][k]+(abs(da)+abs(db)+abs(da+db))/);//因为交易的话不会出现传递式的交易(就是同一个钱币A->B->C,可以直接A->C,所以的话如果da,db正负相同肯定OK啦(此时A,B均是给C,或C给他俩没有彼此交易),如果不同的话只能说明A,B有彼此交易,那么会算重一部分的。
                    }
                }
            }
        }
    }
    if(f[cur][Tar[]][Tar[]]==INF) puts("impossible");
    else printf("%d\n",f[cur][Tar[]][Tar[]]);
}

最新文章

  1. [转]retina屏下支持0.5px边框的情况
  2. notepad++崩溃后文件内容变为NUL的解决方法
  3. python+selenium安装步骤
  4. ASP.NET MVC 4 Optimization的JS/CSS文件动态合并及压缩
  5. JavaEE基础(一)
  6. .net平台的RSA实现以及与Delphi之间的互操作性
  7. CSS媒体查询,CSS根据不同的分辨率显示不同的样式
  8. 客户端无法tcp连接上本地虚拟机的问题(最后是linux防火墙问题)
  9. js中跨域请求原理及2种常见解决方案
  10. JAVA实现AES和MD5加密
  11. HBase的下载、安装与配置
  12. Android 开发 启动activity并且将前面activity全部清空
  13. leetcode 566. 重塑矩阵 c++ 实现
  14. python之tkinter使用-滚动条
  15. 洛谷 P4475 巧克力王国 解题报告
  16. 用户用户组管理:用户管理命令-passwd
  17. monit
  18. c#将Excel数据导入到数据库的实现代码
  19. idea编辑区光标问题
  20. 20155202 实验四 Android开发基础

热门文章

  1. 在Spring Boot中使用内存数据库
  2. Spring MVC 中的http Caching
  3. 深拷贝、浅拷贝与Cloneable接口
  4. c语言实现乘法口诀表
  5. PHP命令执行学习总结
  6. Java——枚举
  7. Navicat,SQL注入,pymysql模块
  8. Phoenix and Distribution(字典序贪心)
  9. 网络流 + 欧拉回路 = B - Sightseeing tour POJ - 1637
  10. 动态代理学习(一)自己动手模拟JDK动态代理