Description

Alice、Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题。不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在清还债务的时候尽可能少的交换现金。比如说,Alice欠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

HINT

对于100%的数据,x1、x2、x3 ≤ |1,000|。

Source

这是一道比较裸的dp(蒟蒻的我居然没看出来)。f[i][j][k]表示前i种面值,A有j元,B有k元的最少交换次数。然后,你懂的(每种面值互相独立),就是转移有点难写,但是,我们是理论计算机科学家,从来不关心算法的实现。

 #include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std; #define inf (1<<25)
#define maxn 1010
int price[] = {,,,,,,};
int all,x[],have[][],aim[],f[][maxn][maxn]; inline int ord(int a) { if (a+ <= ) return a+; return ; } inline void updata(int &now,int key) { if (now > key) now = key; } inline void dp()
{
int i,x,y,s[];
for (i = ;i < ;++i)
for (s[] = ;s[] <= all;++s[])
for (s[] = all - s[];s[] >= ;--s[])
{
if (f[i][s[]][s[]] > inf) continue;
s[] = all - s[] - s[];
for (x = ;x <= have[][i+];++x)
{
if (x * price[i+] > s[]) break;
for (y = ;y <= have[][i+];++y)
{
if (y * price[i+] > s[]) break;
updata(f[i+][s[]-x*price[i+]][s[]-y*price[i+]],f[i][s[]][s[]]+x+y);
}
}
for (x = ;x <= have[][i+];++x)
{
if (x * price[i+] > s[]) break;
for (y = ;y <= have[][i+];++y)
{
if (y * price[i+] > s[]) break;
updata(f[i+][s[]-x*price[i+]][s[]+(x+y)*price[i+]],f[i][s[]][s[]]+x+y);
}
}
for (x = ;x <= have[][i+];++x)
{
if (x * price[i+] > s[]) break;
for (y = ;y <= have[][i+];++y)
{
if (y * price[i+] > s[]) break;
updata(f[i+][s[]+(x+y)*price[i+]][s[]-x*price[i+]],f[i][s[]][s[]]+x+y);
}
}
for (x = ;x <= have[][i+];++x)
{
if (x * price[i+] > s[]) break;
for (y = ;y <= x;++y)
updata(f[i+][s[]-x*price[i+]][s[]+y*price[i+]],f[i][s[]][s[]]+x);
}
for (x = ;x <= have[][i+];++x)
{
if (x * price[i+] > s[]) break;
for (y = ;y <= x;++y)
updata(f[i+][s[]+y*price[i+]][s[]-x*price[i+]],f[i][s[]][s[]]+x);
}
for (x = ;x <= have[][i+];++x)
{
if (x * price[i+] > s[]) break;
for (y = ;y <= x;++y)
updata(f[i+][s[]+y*price[i+]][s[]+(x-y)*price[i+]],f[i][s[]][s[]]+x);
}
}
} int main()
{
memset(f,0x7,sizeof(f)); int i,j;
for (i = ;i <= ;++i) scanf("%d",x+i);
for (i = ;i <= ;++i)
for (j = ;j <= ;++j) scanf("%d",have[i]+j),aim[i] += price[j]*have[i][j];
all = aim[] + aim[] + aim[];
f[][aim[]][aim[]] = ;
for (i = ;i <= ;++i) aim[i] -= x[i],aim[ord(i)] += x[i];
for (i = ;i <= ;++i) if (aim[i] < ) printf("impossible"),exit();
dp();
if (f[][aim[]][aim[]] < inf) printf("%d",f[][aim[]][aim[]]);
else printf("impossible");
return ;
}

BZOJ 1021 循环的债务的更多相关文章

  1. 【BZOJ】【1021】【SHOI2008】Dept循环的债务

    DP 去膜拜题解了>_>玛雅原来是动规…… 让我先理解一下为什么要用动规:这个题根据钱数推方案其实是无从下手的……(线性规划?……事实证明我想多了) 啦-我们先来看个超级简化版的问题:怎么 ...

  2. BZOJ 1021 [SHOI2008]Debt 循环的债务

    1021: [SHOI2008]Debt 循环的债务 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 694  Solved: 356[Submit][S ...

  3. BZOJ 1021: [SHOI2008]Debt 循环的债务( dp )

    dp(i, j, k)表示考虑了前i种钱币(从小到大), Alice的钱数为j, Bob的钱数为k, 最小次数. 脑补一下可以发现, 只有A->B.C, B->A.C, C->A.B ...

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1021 如果A收到了B的1张10元,那么A绝对不会把这张10元再给C 因为这样不如B直接给C优 由此可 ...

  5. bzoj1021 [SHOI2008]Debt 循环的债务

    前天打了一场比赛,让我知道自己Dp有多弱了,伤心了一天,没刷bzoj. 昨天想了一天,虽然知道几何怎么搞,但我还是不敢写,让我知道自己几何有多弱了,伤心了一天,没刷bzoj 1021: [SHOI20 ...

  6. BZOJ_1021_[SHOI2008]_Debt循环的债务_(DP)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1021 三个人相互欠钱,给出他们每个人各种面额的钞票各有多少张,求最少需要传递多少张钞票才能把账 ...

  7. 【BZOJ1021】[SHOI2008]循环的债务(动态规划)

    [BZOJ1021][SHOI2008]循环的债务(动态规划) 题面 BZOJ 洛谷 题解 感觉以前的题目都好小清新啊,我这种智商丢失的选手完全写不动. 这题看着就像一个\(dp\),并且我们发现每种 ...

  8. 【SHOI2008】JZOJ2020年9月5日提高组 循环的债务

    CSP-2020倒计时:36天 [SHOI2008]JZOJ2020年9月5日提高组 循环的债务 题目 Description Alice.Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有 ...

  9. 1021: [SHOI2008]Debt 循环的债务 - BZOJ

    Description Alice.Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题.不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在清还债务的 ...

随机推荐

  1. [Redux] Supplying the Initial State

    We will learn how to start a Redux app with a previously persisted state, and how it merges with the ...

  2. 关于 Android 进程保活,你所需要知道的一切

    早前,我在知乎上回答了这样一个问题:怎么让 Android 程序一直后台运行,像 QQ 一样不被杀死?.关于 Android 平台的进程保活这一块,想必是所有 Android 开发者瞩目的内容之一.你 ...

  3. JS 拼凑字符串

    和Java一样,JS中直接用"+"号拼凑字符串是很耗费资源的,所以在大量拼凑字符串的情景中,我们也需要一个类似于StringBuffer的工具, 下面利用Array.join()方 ...

  4. 自己做的萌萌哒的js宠物挂件~

    OwO萌物v1.1 类似wp伪春菜,但纯js不用后端,且可定制程度非常高~,3个人格示例,需要的童鞋自提 仙六 - 越祈 作者:正逍遥0716 2016/5/15 CLANNAD - 藤林杏 作者:正 ...

  5. cocos2dx Hello world 创建

    环境搭建好后,就要开始创建自己的第一个hello world项目了 因为没有安装其他的插件,所以最开始只能手动创建 首先通过cmd 进入你的cocos2dx的路径下: D:\soft\cocos2d- ...

  6. angularJS随笔

    1.作用域 基于作用域的事件传播 作用域可以像DOM节点一样,进行事件的传播.主要是有两个方法: broadcasted :从父级作用域广播至子级 scope emitted :从子级作用域往上发射到 ...

  7. Datum Form Goole Android

    1. <TurboChargeYourUI-How to make your AndroidUI fast and efficient> 2. <The World of List ...

  8. ViewPager和SwipeRefreshLayout之间嵌套使用时发生"事件"冲突

    有时候我们会有一种需求,一个ViewPager有n个页面,每个页面是一个Fragment,在Fragment中使用了具有垂直滑动属性的控件,比如SwipeRefreshLayout!!! 这时二者之间 ...

  9. Visual C#实现Windows信使服务

    现在有很多网络管理软件都具备网络上信息实时传送的功能,虽然有些网络通讯软件功能比较强大,有的软件不仅可以传送文本信息,还可以传送二进制文件等.但 它们都有一个无法克服的缺点,那就是分发比较困难,信息传 ...

  10. framework not found -fno-arc编译错误

    由于我是刚接手的代码  然后我拿来运行根本就是运行不了的  然后需要在linker 那边删除点东西就可以了. 把下边的两个删除就可以了 关于other linker flags 的介绍 请参考http ...