$bzoj1021-SHOI2008\ Debt$ 循环的债务 $dp$
题面描述
- \(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\)张钞票被交换过。没过多久他们就发现这是一个很棘手的问题,于是他们找到了精通数学的你为他们解决这个难题。
输入格式
输入的第一行包括三个整数:\(x_1\)、\(x_2\)、\(x_3\),\(-10^3\leq x_1,x_2,x_3\leq 10^3\),其中 \(x_1\)代表\(Alice\)欠\(Bob\)的钱(如果\(x_1\)是负数,说明\(Bob\)欠了\(Alice\)的钱)以此类推
接下来有三行,每行包括6个自然数:\(a_{100}\) \(a_{50}\) \(a_{20}\) \(a_{10}\) \(a_{5}\) \(a_{1}\) \(b_{100}\) \(b_{50}\) \(b_{20}\) \(b_{10}\) \(b_{5}\) \(b_{1}\) \(c_{100}\) \(c_{50}\) \(c_{20}\) \(c_{10}\) \(c_{5}\) \(c_{1}\) \(a_{100}\)表示\(Alice\)拥有的\(100\)元钞票张数,\(b_{50}\)表示\(Bob\)拥有的\(50\)元钞票张数,以此类推。另外,我们保证有\(a_{10}+a_5+a_1\leq 30\),\(b_{10}+b_5+b_1\leq 30\),\(c_{10}+c_5+c_1\leq 30\),而且三人总共拥有的钞票面值总额不会超过\(10^3\)。
输出格式
- 如果债务可以还清,则输出需要交换钞票的最少张数;如果不能还清,则输出“impossible”(注意单词全部小写,输出到文件时不要加引号)。
题解
首先看到这题,我们稍加思考便能够发现,这个问题的初状态每个人拥有的钱数,以及终状态每个人拥有的钱数是固定的。
第一次看到题,我一直关注与钞票的交换上,只觉得这个交换方式十分复杂,没有办法用一种有效的方式转化。于是就\(YY\)了一个\(A^*\)出来,但过不了全部的点
- 具体就是,把\(A^*\)的估价函数\(g(x)\)设为 不考虑每个人每种钱拥有的张数的情况下
- \(\sum_{i=1}^3\)第\(i\)个人现有\(x\)元,终状态该人有\(y\)元,从\(x\)元变到\(y\)元最少要向他人交换几张钞票
- 这一部分可以用无限背包做
- 具体就是,把\(A^*\)的估价函数\(g(x)\)设为 不考虑每个人每种钱拥有的张数的情况下
但像我们最初考虑该问题是想到的初状态与终状态固定,受到物理的保守力只需考虑始、末状态,不需考虑中间过程的启发,我们其实不需要知道这些钞票是如何进行换的,我们只关心换完之后每个人所拥有的钱。
这样一来,我们就会发现,每种币值的钞票相对独立,因此我们将每种币值的钞票独立开来,成为每层的状态。
如此一来,我们可以设计出这样的\(dp\)方程
记\(f_{i,x,y,z}\)表示使用前\(i\)种币值的钞票进行交换后,三个人各有\(x,y,z\)元时最少的钞票交换次数,记\(b_i\)表示第\(i\)种钞票的币值,\(k_i\)表示每个人给出第\(i\)种钞票的张数(可正可负)
则 他们三人之间交换第\(i\)种钞票的总张数为\(chg=\frac{|k_1|+|k_2|+|k_3|}{2}\)
- \[f_{i,x-k_1*b_i,y-k_2*b_i,z-k_3*b_i}=f_{i-1,x,y,z}+chg\\
保证k_1+k_2+k_3=三人拥有第i种钞票的总张数
\]
然后,我们不难发现\(x+y+z\)恒等三人拥有的总钱数
因此我们可以降一维变成
- \[f_{i,x-k_1*b_i,y-k_2*b_i}=f_{i-1,x,y}+chg\\
k_3=三人拥有第i种钞票的总张数-k_1-k_2\\
chg=\frac{|k_1|+|k_2|+|k_3|}{2}
\]
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e3+5;
const int b[10]={0,100,50,20,10,5,1};
int mon[4][10];
int x1,x2,x3,s[4];
int sum;
int f[7][MAXN][MAXN];
int main(){
scanf("%d%d%d",&x1,&x2,&x3);
for (int i=1;i<=3;i++){
for (int j=1;j<=6;j++){
scanf("%d",&mon[i][j]);
sum+=mon[i][j]*b[j];
}
}
// cout<<"done"<<endl;
for (int i=1;i<=3;i++){
for (int j=1;j<=6;j++) s[i]+=mon[i][j]*b[j];
}
if (s[1]-x1+x3>sum||s[2]+x1-x2>sum||s[3]-x3+x2>sum) return printf("impossible\n"),0;
memset(f,63,sizeof(f)); f[0][s[1]][s[2]]=0;
for (int i=1;i<=6;i++){
for (int j=0;j<=sum;j++){
for (int k=0;k+j<=sum;k++){
if (f[i-1][j][k]>=1e9) continue;
int cnt=mon[1][i]+mon[2][i]+mon[3][i];
for (int x=0;x<=cnt;x++){
for (int y=0;y+x<=cnt;y++){
int z=cnt-x-y;
int lx=mon[1][i]-x;
int ly=mon[2][i]-y;
int lz=mon[3][i]-z;
int chg=(abs(lx)+abs(ly)+abs(lz))/2;
if (j-lx*b[i]+k-ly*b[i]>sum) continue;
if (j<lx*b[i]||k<ly*b[i]) continue;
f[i][j-lx*b[i]][k-ly*b[i]]=min(f[i][j-lx*b[i]][k-ly*b[i]],f[i-1][j][k]+chg);
}
}
}
}
}
int ans=f[6][s[1]-x1+x3][s[2]-x2+x1];
if (ans>=1e9) printf("impossible\n");
else printf("%d\n",ans);
return 0;
}
随机推荐
- [GO]结构体的值传递和地址传递
package main import "fmt" type student struct { id int name string sex byte age int addr s ...
- Mysql设计索引的原则
内容来自书籍<深入浅出MySQL++数据库开发.优化与管理维护+第2版+唐汉明> 设计索引的原则1. 搜索的索引列,不一定是所要选择的列.换句话说,最适合索引的列是出现在 WHERE 子句 ...
- 编写高质量代码改善C#程序的157个建议——建议144:一个方法只做一件事
建议144:一个方法只做一件事 “单一职责原则”(SRP)要求每一个类型只负责一件事情.我们将此概念扩展到方法上,就变成了:一个方法只做一件事. 回顾上一建议的代码,LocalInit和RemoteI ...
- Windows pip
pip 最常用命令(go语言用go get) 显示版本和路径 pip --version 获取帮助 pip --help 升级 pip pip install -U pip 如果这个升级命令出现问题 ...
- 阿里云ECS云服务器编译安装PHP遇到virtual memory exhausted: Cannot allocate memory
阿里云编译安装php时遇到virtual memory exhausted: Cannot allocate memory 买了个服务器, 1G 的内存阿里云服务器,编译东西按说应该够了,安装相关的内 ...
- mybatis--mapper配置总结
mapper介绍 mapper使用规则:按业务划分,一个业务模块相关的sql均定义在一个mapper文件 mapper的xml格式: doctype: <!DOCTYPE mapper PUBL ...
- [LeetCode 题解]: Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- [转]Control的Invoke和BeginInvoke
转自:Control的Invoke和BeginInvoke 作者:Kuffy Wang 近日,被Control的Invoke和BeginInvoke搞的头大,就查了些相关的资料,整理如下.感谢这篇文 ...
- c# mvc 第三方定时 FluentScheduler
开头无关内容,可略过: 最近工作和生活都忙的不可开交了. 工作和生活上都不太顺利,5月底出了车祸回家养伤.6月忙着今年的大事. 给自己鼓鼓励吧 最近重拾nodejs和python,也给自己动力,继续学 ...
- ViewController关闭自身返回前一个View
点击按钮号响应的函数 @IBAction func onBack(sender : AnyObject) { self.dismissViewControllerAnimated(true, comp ...