• 题面描述

    • \(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\)元最少要向他人交换几张钞票
      • 这一部分可以用无限背包做
    • 但像我们最初考虑该问题是想到的初状态与终状态固定,受到物理的保守力只需考虑始、末状态,不需考虑中间过程的启发,我们其实不需要知道这些钞票是如何进行换的,我们只关心换完之后每个人所拥有的钱。

    • 这样一来,我们就会发现,每种币值的钞票相对独立,因此我们将每种币值的钞票独立开来,成为每层的状态。

    • 如此一来,我们可以设计出这样的\(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;
}

随机推荐

  1. 前端福利之改变placeholder颜色的方法(转)

    之前拿到一个设计图,Placeholder是白色的,所以就查看了一下改变placeholder的方法: input::-webkit-input-placeholder { /* WebKit bro ...

  2. 白话浅说TCP/UDP面向连接,面向无连接的区别

    TCP是面向连接的UDP是面向无连接的就是这种关系了 TCP(Transmission Control Protocol,传输控制协议) UDP(User Datagram Protocol,用户数据 ...

  3. tomcat 无法clean 的bug

    如果你打开类似这种的文件夹了,那恭喜你,你无法正常clean E:\e\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0 请关 ...

  4. c语言和java以及安卓和苹果

    苹果手机是本地,没有中间环节,速度快,基于Linux系统 安卓是通过虚拟机,影响速度 就像c语言和java c适用于架构小的地方,因为直接编译运行 而java用于架构比较大的地方,启动慢,启动之后效率 ...

  5. VC中CDC与HDC的区别以及二者之间的转换

    CDC是MFC的DC的一个类 HDC是DC的句柄,API中的一个类似指针的数据类型. MFC类的前缀都是C开头的 H开头的大多数是句柄 这是为了助记,是编程读\写代码的好的习惯. CDC中所有MFC的 ...

  6. Centos7 因内存 可用大小不足,被killed的解决办法

    Linux的内存分配采取的是一种更加积极的分配策略,它假设应用申请了内存空间后并不会立即去使用它,所以允许一定量的超售,当应用真的需要使用它的时候,操作系统可能已经通过回收了其他应用的内存空间而变得有 ...

  7. 模仿w3c school的示例导航栏

    近日学习HTML,恰巧学习过程中看见w3cschool的示例导航栏看上去很不错,适合新手练习,于是模仿着做了一个. 示例导航栏如下图所示 导航栏自然使用li标签来做,a标签控制背景颜色和鼠标放入的特效 ...

  8. Android通知栏介绍与适配总结(上篇)

    此文已由作者黎星授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 由于历史原因,Android在发布之初对通知栏Notification的设计相当简单,而如今面对各式各样的通知 ...

  9. Django-05模型层之单表操作1

    7.1 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开 ...

  10. flutter 保存图片到本地

    f'lutter 图片的保存 分为俩步: 1.开启存储图片权限开启权限需要用到permission_handler pubspec 添加 permission_handler: ^3.0.1下载包就可 ...