前天打了一场比赛,让我知道自己Dp有多弱了,伤心了一天,没刷bzoj。

昨天想了一天,虽然知道几何怎么搞,但我还是不敢写,让我知道自己几何有多弱了,伤心了一天,没刷bzoj

1021: [SHOI2008]Debt 循环的债务

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 685  Solved: 350
[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

题意:如题意所述

分析:没写题意是因为这里有关于题意的转化,

一开始在思考债务的循环关系,十分复杂

有A->B->C这样的连环给的关系,但细想后发现

连环给钱的关系是不可能的,A->B->C肯定不如A->B,A->C这样好(对于同一种币值的货币来说)

根据欠债的关系,就能推断出目标状态的资金,对吧!?

初始资金能算出来,对吧!?

那。。。这不就是给出初始状态、结束状态,以及几种变化方式,求最少步数的类似问题!?

变化方式根据上面的分析,如果我们将每种币值的货币分开考虑,那么,就只有6种方式

A->B,C     B->A,C     C->A,B

AB->C      AC->B      BC->A

其中,A->B,C包含了 A->B,A->C两种(意思就是给0张货币也算给)

那么就可以得出Dp状态(其实类似于记忆化搜索)

Dp[i][M1][M2]表示用前i中货币,达到Alice有M1元,Bob有M2元,Cynthia有(Sum-M1-M2)元的状态的最少交换钱的张数

转移上面说了,整个过程相当于记忆化搜索

其中有个剪枝

如果某个人的现有钱数与目标钱数的差额(现有-目标)%剩下的币值的GCD(比如说现在算到第 i 种货币,那么就是 第 i+1种到第 6 种的币值的Gcd) != 零(不能整除)

那么显然不能大刀目标,因为剩下的币值都可以表示成 k*Gcd的形式,若不整除于Gcd,显然达不到

综上所述,此题得解

 #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <ctime>
using namespace std;
typedef long long LL;
#define For(i, s, t) for(int i = (s); i <= (t); i++)
#define Ford(i, s, t) for(int i = (s); i >= (t); i--)
#define Rep(i, t) for(int i = (0); i < (t); i++)
#define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
#define MIT (2147483647)
#define INF (1000000001)
#define MLL (1000000000000000001LL)
#define sz(x) ((int) (x).size())
#define clr(x, y) memset(x, y, sizeof(x))
#define puf push_front
#define pub push_back
#define pof pop_front
#define pob pop_back
#define ft first
#define sd second
#define mk make_pair
inline void SetIO(string Name) {
string Input = Name+".in",
Output = Name+".out";
freopen(Input.c_str(), "r", stdin),
freopen(Output.c_str(), "w", stdout);
} const int N = , M[] = {, , , , , };
const int G[] = {, , , , , };
typedef pair<int, int> II;
int Sum, Debt[], St[], Ed[], Cash[][];
int Dp[][N][N], Visit[][N][N];
queue<II> Q[];
int Ans = INF; inline void Input() {
Rep(i, ) scanf("%d", &Debt[i]);
Rep(i, )
Rep(j, )
scanf("%d", &Cash[i][-j]);
} inline void Push(int w, int A, int B, int Step) {
if(w >= ) {
int Last[], C = Sum-A-B;
Rep(i, ) Last[i] = Ed[i];
Last[] -= A, Last[] -= B, Last[] -= C;
Rep(i, )
if(Last[i]%G[w]) return;
} int p = (w+)%;
if(Visit[p][A][B] == w) Dp[p][A][B] = min(Dp[p][A][B], Step);
else Q[p].push(mk(A, B)), Dp[p][A][B] = Step, Visit[p][A][B] = w;
if(A == Ed[] && B == Ed[]) Ans = min(Ans, Step);
} inline void Solve() {
Rep(i, ) {
Rep(j, ) St[i] += Cash[i][j]*M[j];
Sum += St[i], Ed[i] += St[i];
Ed[i] -= Debt[i], Ed[(i+)%] += Debt[i];
}
Rep(i, )
Rep(j, Sum)
Rep(k, Sum) Visit[i][j][k] = -; Push(-, St[], St[], );
int Last = , S[], _Step, To, F1, F2, Front, T1, T2;
Rep(w, ) {
Last ^= ;
while(sz(Q[Last])) {
II State = Q[Last].front();
Q[Last].pop(); // One Get Front Two
Rep(i, ) {
To = i, F1 = (i+)%;
F2 = ++-F1-To;
Rep(C1, Cash[F1][w]+)
Rep(C2, Cash[F2][w]+) {
S[] = State.ft, S[] = State.sd;
S[] = Sum-S[]-S[]; _Step = Dp[Last][S[]][S[]]+C1+C2;
S[To] += (C1+C2)*M[w],
S[F1] -= C1*M[w], S[F2] -= C2*M[w];
Push(w, S[], S[], _Step);
}
} // One Give To Two
Rep(i, ) {
Front = i, T1 = (i+)%;
T2 = ++-Front-T1;
Rep(C1, Cash[Front][w]+)
Rep(C2, Cash[Front][w]-C1+) {
S[] = State.ft, S[] = State.sd;
S[] = Sum-S[]-S[]; _Step = Dp[Last][S[]][S[]]+C1+C2;
S[Front] -= (C1+C2)*M[w];
S[T1] += C1*M[w], S[T2] += C2*M[w];
Push(w, S[], S[], _Step);
}
}
}
} if(Ans == INF) puts("impossible");
else printf("%d\n", Ans);
} int main() {
SetIO("");
Input();
Solve();
return ;
}

bzoj1021 [SHOI2008]Debt 循环的债务的更多相关文章

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

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

  2. [bzoj1021][SHOI2008]Debt 循环的债务 (动态规划)

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

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

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

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

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

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

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

  6. 【BZOJ 1021】[SHOI2008]Debt 循环的债务

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1021 [题意] [题解] 设f[i][j][k]表示前i种面值的钱币; 第一个人当前的 ...

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

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

  8. [SHOI 2008]Debt 循环的债务

    Description 题库链接 A 欠 B \(x_1\) 元, B 欠 C \(x_2\) 元, C 欠 A \(x_3\) 元.现每人手上各有若干张 100,50,20,10,5,1 钞票.问至 ...

  9. $bzoj1021-SHOI2008\ Debt$ 循环的债务 $dp$

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

随机推荐

  1. U盘安装Linux安装报错及解决方案

    导读 从网上看到了<Linux就该这么学>后,偏离软件行业多年的我下定决心回归!这篇文章是我这一个小白的亲身经历,希望能被采纳! 开始按照<Linux就该这么学>中所讲在自己的 ...

  2. 5款Linux最佳照片管理软件

    在谈到 Linux 中的应用程序时,对于不同的用户.不同的使用场景以及不同的使用习惯,在同一类应用当中,总会有多种软件可供选择和备选.就 Linux 中的照片管理软件来说,相信此前的 Google P ...

  3. 技术分享:WIFI钓鱼的入门姿势

    简介 该实验先是搭建一个测试环境,然后创建一个假的无线接入点,把网络连接连接到假的接入点并且强迫用户连接假的无线点. 事先准备 1.无线网卡:无线网卡用于数据包的嗅探和注入. 2. Backtrack ...

  4. jQuery获取Select选择的Text和 Value(转)

    radio: radio: var item = $('input[name=items][checked]').val(); var item = $('input[name=items]:chec ...

  5. Android的Observable和iOS的NotificationCenter

    使用起来很类似,参看以下网址http://stackoverflow.com/questions/10327200/equivalent-of-ios-nsnotificationcenter-in- ...

  6. Android 中4种屏幕尺寸

    具体信息,请参考 Android 官方文档 Supporting Multiple Screens small(屏幕尺寸小于3英寸左右的布局),  normal(屏幕尺寸小于4.5英寸左右), lar ...

  7. 利用 FFmpeg palettegen paletteuse 生成接近全色的 gif 动画

    下载FFmpeg-VideoToGif-v1.0.bat.7z FFmpeg 2.6 及以上版本有效 未使用palette时 使用palette后 @echo off set inFile=2015. ...

  8. 9.Python笔记之面向对象高级部分

    类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的 ...

  9. codeforces 474D.Flowers 解题报告

    题目链接:http://codeforces.com/problemset/problem/474/D 题目意思:Marmot 吃两种类型的花(实在难以置信呀--):red 或者 white,如果要吃 ...

  10. 【mysql】用navicat连接虚拟机mysql出现错误代码(10038)

    来源: http://www.cnblogs.com/ohmydenzi/p/5521121.html http://blog.csdn.net/chana1101/article/details/3 ...