【BZOJ】【1021】【SHOI2008】Dept循环的债务
DP
去膜拜题解了>_>玛雅原来是动规……
让我先理解一下为什么要用动规:这个题根据钱数推方案其实是无从下手的……(线性规划?……事实证明我想多了)
啦~我们先来看个超级简化版的问题:怎么判无法还清?正着判很麻烦对不对= =(其实是我没想……)
那么我们倒着来考虑:有哪些状态是我们通过交换钱币能够到达的,这个可以递推对不>_>
现在我们就知道哪些状态我们是可以到达的了……再多想一下……递推……如果我们依次考虑每种面额的交换策略,顺便也就知道了我们到达这个状态的最小交换次数对吧?
原因:因为每种面值只有6种策略(给出钱的是一个人,3种,给出钱的是两个人,3种),且不同面值之间的交换互不影响(这不是废话吗!我手里有多少张10块的难道还会影响我手里100块的张数?可是我一开始绕进这个弯里没走出来TAT)
(P.S.看到这里你就可以去写题了,因为我动规方程比较奇葩……自己想的时候又把自己坑了
我是让$f[i][j][k]$表示当前a手里有 j 块钱,b手里有 k 块钱,现在该考虑第 i 种面额的钞票(但是还没有对第 i 种钞票进行分配!!我忘了啊啊啊!!!看了题解以后跟人家的方法搞混了?>_>)
那么我是分3种情况讨论的(将上面的6种情况组合了一下)……1. a给b、c或是b、c给a ; 2.b给a、c或是a、c给b;3.c给a、b或是a、b给c。
明显可行的状态比数组大小小得多,所以就用了队列来保存/扩展可行状态(类似记忆化搜索的策略吧)
(不过我这种姿势明显是比较捉急的……不过也能过>_>想看 快/短 一点的做法请戳@regina8023 @rausen)
自我感觉我写这题的动规的姿势还是蛮特别的,而且还是第666个提交 2333~沾沾自喜一下(>_<)~
/**************************************************************
Problem: 1021
User: Tunix
Language: C++
Result: Accepted
Time:784 ms
Memory:52136 kb
****************************************************************/ //BZOJ 1021
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int M=1e6+,INF=~0u>>;
typedef long long LL;
/******************tamplate*********************/
const int money[]={,,,,,,};
int a[],b[],c[],sa,sb,sc,ea,eb,ec;
int n,m,f[][][],tot;
bool inq[][][];
struct node{
int x,y,z;
}Q[M];
void dp(){
F(i,,) F(j,,tot) F(k,,tot) f[i][j][k]=INF;
int l=,r=-;
Q[++r]=(node){,sa,sb}; f[][sa][sb]=; inq[][sa][sb]=;
while(l<=r){
node now=Q[l++];
int x=now.x,y=now.y,z=now.z;
inq[x][y][z]=;
if (x==) continue;
if (f[x+][y][z]>f[x][y][z]){
f[x+][y][z]=f[x][y][z];
if (!inq[x+][y][z]){
Q[++r]=(node){x+,y,z};
inq[x+][y][z]=;
}
}
F(i,-b[x],a[x]) F(j,-c[x],a[x]-i){
int ty=y-(i+j)*money[x],tz=z+i*money[x];
if (ty<) break;
if (f[x+][ty][tz]>f[x][y][z]+abs(i)+abs(j)){
f[x+][ty][tz]=f[x][y][z]+abs(i)+abs(j);
if (!inq[x+][ty][tz]){
Q[++r]=(node){x+,ty,tz};
inq[x+][ty][tz]=;
}
}
}
F(i,-a[x],b[x]) F(j,-c[x],b[x]-i){
int ty=y+i*money[x],tz=z-(i+j)*money[x];
if (tz<) break;
if (f[x+][ty][tz]>f[x][y][z]+abs(i)+abs(j)){
f[x+][ty][tz]=f[x][y][z]+abs(i)+abs(j);
if (!inq[x+][ty][tz]){
Q[++r]=(node){x+,ty,tz};
inq[x+][ty][tz]=;
}
}
}
F(i,-a[x],c[x]) F(j,-b[x],c[x]-i){
int ty=y+i*money[x],tz=z+j*money[x];
if (ty+tz>tot) break;
if (f[x+][ty][tz]>f[x][y][z]+abs(i)+abs(j)){
f[x+][ty][tz]=f[x][y][z]+abs(i)+abs(j);
if (!inq[x+][ty][tz]){
Q[++r]=(node){x+,ty,tz};
inq[x+][ty][tz]=;
}
}
}
}
// F(i,1,7) F(j,0,tot) F(k,0,tot)
// if (f[i][j][k]!=INF)printf("f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k]);
if (f[][ea][eb]==INF||ea<||eb<||ec<||ea+eb+ec>tot) puts("impossible");
else printf("%d\n",f[][ea][eb]);
} int main(){
#ifndef ONLINE_JUDGE
freopen("1021.in","r",stdin);
freopen("1021.out","w",stdout);
#endif
int x1=getint(),x2=getint(),x3=getint();
F(i,,) {a[-i]=getint();sa+=a[-i]*money[-i];}
F(i,,) {b[-i]=getint();sb+=b[-i]*money[-i];}
F(i,,) {c[-i]=getint();sc+=c[-i]*money[-i];}
tot=sa+sb+sc;
ea=sa-x1+x3; eb=sb-x2+x1; ec=sc-x3+x2;
dp();
return ;
}
1021: [SHOI2008]Debt 循环的债务
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 666 Solved: 336
[Submit][Status][Discuss]
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
【BZOJ】【1021】【SHOI2008】Dept循环的债务的更多相关文章
- 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 ...
- 1021: [SHOI2008]Debt 循环的债务 - BZOJ
Description Alice.Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题.不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在清还债务的 ...
- bzoj1021 [SHOI2008]Debt 循环的债务
前天打了一场比赛,让我知道自己Dp有多弱了,伤心了一天,没刷bzoj. 昨天想了一天,虽然知道几何怎么搞,但我还是不敢写,让我知道自己几何有多弱了,伤心了一天,没刷bzoj 1021: [SHOI20 ...
- bzoj千题计划111:bzoj1021: [SHOI2008]Debt 循环的债务
http://www.lydsy.com/JudgeOnline/problem.php?id=1021 如果A收到了B的1张10元,那么A绝对不会把这张10元再给C 因为这样不如B直接给C优 由此可 ...
- BZOJ_1021_[SHOI2008]_Debt循环的债务_(DP)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1021 三个人相互欠钱,给出他们每个人各种面额的钞票各有多少张,求最少需要传递多少张钞票才能把账 ...
- 【BZOJ 1021】[SHOI2008]Debt 循环的债务
[题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1021 [题意] [题解] 设f[i][j][k]表示前i种面值的钱币; 第一个人当前的 ...
- BZOJ.1021.[SHOI2008]循环的债务(DP)
题目链接 不同面额的钞票是可以分开考虑的. ↑其实并不很明白具体(证明?),反正是可以像背包一样去做. f[x][i][j]表示用前x种面额钞票满足 A有i元 B有j元 (C有sum-i-j)所需交换 ...
- [bzoj1021][SHOI2008]Debt 循环的债务 (动态规划)
Description Alice. Bob和Cynthia总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题.不过,鉴别钞票的真伪是一件很麻烦的事情,于是他 们决定要在清还债 ...
随机推荐
- c#自定义控件属性面板及选择资源设置
博客转移到 http://jacean.github.io/ 继续分享编程经验 因为要做流体布局,但两个控件没办法组合,就做自定义控件.这个控件需要一个text设置文本,一个pic设置图片显示,图片通 ...
- javascript中match和RegExp组合用法
function getCookie(name)//取cookies函数 { //coook中document.cookie = "age=12; name=1.css"; var ...
- kettle的job
1.首先创建一个job 2.拖拽组件形成下面的图 这里需要注意,在作业中的连线分为三类: 黄色锁的线:这个步骤执行之后,无论失败与否都会执行下一个步骤 绿色对号线:步骤执行成功了,才会执行下一个步骤. ...
- ios 异步处理耗时操作
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_asy ...
- 微信分享朋友链接显示js代码
通常自己做的一个页面想通过微信像朋友分享时,展示的标题和描述都是不是自己想要的,自己查了一些资料,原来是通过js来进行控制 展示效果如下: 标题.描述.还有分享的图片都是有js来控制的. js代码如下 ...
- ORACLE 单实例完全卸载数据库
1.用oracle用户登录如果要再次安装, 最好先做一些备份工作.包括用户的登录脚本,数据库自动启动关闭的脚本,和Listener自动启动的脚本.要是有可能连创建数据库的脚本也保存下来 2.使用SQL ...
- C++中int *p[4]和 int (*q)[4]的区别
这俩兄弟长得实在太像,以至于经常让人混淆.然而细心领会和甄别就会发现它们大有不同. 前者是指针数组,后者是指向数组的指针.更详细地说. 前: 指针数组;是一个元素全为指针的数组.后: 数组指针;可以直 ...
- React Native分析(index.ios.js)
定义创建组件MyComponent(index.ios.js): 'use strict' var React = require('react-native'); var { AppRegistry ...
- Power Map 入门
Excel 的 Microsoft Power Map是三维 (3-D) 数据的可视化工具,允许您以新的方式看信息.电源映射允许您发现您可能看不到传统的二维 (2-d) 表和图中的见解. 使用Powe ...
- iOS 各种系统文件目录 临时,缓存,document,lib,归档,序列化
/** 1:Documents:应用中用户数据可以放在这里,iTunes备份和恢复的时候会包括此目录 2:tmp:存放临时文件,iTunes不会备份和恢复此目录,此目录下文件可能会在应用退出后删除 3 ...