BZOJ 1021 循环的债务
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 循环的债务的更多相关文章
- 【BZOJ】【1021】【SHOI2008】Dept循环的债务
DP 去膜拜题解了>_>玛雅原来是动规…… 让我先理解一下为什么要用动规:这个题根据钱数推方案其实是无从下手的……(线性规划?……事实证明我想多了) 啦-我们先来看个超级简化版的问题:怎么 ...
- BZOJ 1021 [SHOI2008]Debt 循环的债务
1021: [SHOI2008]Debt 循环的债务 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 694 Solved: 356[Submit][S ...
- BZOJ 1021: [SHOI2008]Debt 循环的债务( dp )
dp(i, j, k)表示考虑了前i种钱币(从小到大), Alice的钱数为j, Bob的钱数为k, 最小次数. 脑补一下可以发现, 只有A->B.C, B->A.C, C->A.B ...
- bzoj千题计划111:bzoj1021: [SHOI2008]Debt 循环的债务
http://www.lydsy.com/JudgeOnline/problem.php?id=1021 如果A收到了B的1张10元,那么A绝对不会把这张10元再给C 因为这样不如B直接给C优 由此可 ...
- bzoj1021 [SHOI2008]Debt 循环的债务
前天打了一场比赛,让我知道自己Dp有多弱了,伤心了一天,没刷bzoj. 昨天想了一天,虽然知道几何怎么搞,但我还是不敢写,让我知道自己几何有多弱了,伤心了一天,没刷bzoj 1021: [SHOI20 ...
- BZOJ_1021_[SHOI2008]_Debt循环的债务_(DP)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1021 三个人相互欠钱,给出他们每个人各种面额的钞票各有多少张,求最少需要传递多少张钞票才能把账 ...
- 【BZOJ1021】[SHOI2008]循环的债务(动态规划)
[BZOJ1021][SHOI2008]循环的债务(动态规划) 题面 BZOJ 洛谷 题解 感觉以前的题目都好小清新啊,我这种智商丢失的选手完全写不动. 这题看着就像一个\(dp\),并且我们发现每种 ...
- 【SHOI2008】JZOJ2020年9月5日提高组 循环的债务
CSP-2020倒计时:36天 [SHOI2008]JZOJ2020年9月5日提高组 循环的债务 题目 Description Alice.Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有 ...
- 1021: [SHOI2008]Debt 循环的债务 - BZOJ
Description Alice.Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题.不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在清还债务的 ...
随机推荐
- 查看mysql数据库及表编码格式
1.查看数据库编码格式 mysql> show variables like 'character_set_database'; 2.查看数据表的编码格式 mysql> show crea ...
- android tips—启动Emergency call拨号盘
Intent intent = new Intent(); intent.setAction("com.android.phone.EmergencyDialer.DIAL"); ...
- 教你搞定Android自定义View
Android App开发过程中,很多时候会遇到系统框架中提供的控件无法满足我们产品的设计需求,那么这时候我们可以选择先Google下有没有比较成熟的开源项目可以让我们用,当然现在Github上面的项 ...
- cocos2dx实现android的对讯飞语音的合成(语言朗读的实现)
事实上非常easy,只是有些细节须要注意. 关于讯飞语音在android上的应用,大家须要自己去下载SDK,然后依照讯飞语音提供的api在自己的android的Demo上执行成功,那东西也相当的简单. ...
- Unix网络编程代码 第13章 守护进程和inetd超级服务器
1. 概述 守护进程是在后台运行且不与任何控制终端关联的进程.unix系统通常有很多守护进程在后台运行,执行不同的管理任务. 守护进程没有控制终端通常源于它们由系统初始化脚本启动.然而守护进程也 ...
- ASP.NET MVC 第五回 ActionResult的其它返回值
我们上边所看到的Action都是return View();我们可以看作这个返回值用于解析一个aspx文件.而它的返回类型是ActionResult如 public ActionResult Inde ...
- 学习java随笔第一篇:搭建java平台(java se)
电脑系统:windows8 在这里介绍一下java平台的3个版本: Java SE--Java Standard Edition,Java的标准版,主要用于桌面级的应用和数据库开发. Java EE- ...
- JSP自定义标签库
总所周知,JSP自定义标签库,主要是为了去掉JSP页面中的JAVA语句 此处以格式化输出时间戳为指定日期格式为例,简单介绍下JSP自定义标签的过程. 编写标签处理类(可继承自javax.servlet ...
- google的西联汇款可以使用工行代收
- JavaScript中style.left与offsetLeft的区别
今天在制作焦点轮播图的时候,遇到一个问题,在使用style.left获取图片的位置时,怎么也获取不到.换用offsetLeft就能够成功获取到了.虽然实现了我想要的效果,但是还是不甘心啊,没有找到原因 ...