• 题面描述

    • \(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. MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error

    今天购物车突然不能添加了,发现redis报错了,重启了一下好了,一会又报错了. 错误信息: MISCONF Redis is configured to save RDB snapshots, but ...

  2. CodeForces 682A Alyona and Numbers (水题,数学)

    题意:给定两个数 m,n,问你在从1到 n,和从 1到 m中任选两个数加起来是5的倍数,问你有多少个. 析:先计算 m 和 n中有多少个取模5是从0到4的,然后根据排列组合,相乘就得到了小于等于 m ...

  3. 团体程序设计天梯赛L2-009 抢红包 2017-03-22 19:18 131人阅读 评论(0) 收藏

    L2-009. 抢红包 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 没有人没抢过红包吧-- 这里给出N个人之间互相发红包.抢 ...

  4. NSArray去除重复元素

    直接上代码吧! 1.可以创建一个新的数组,对需要去除重复的数组进行遍历,如果新数组不包含就数组,那么添加元素,如果包含就不添加. NSMutableArray *array = [NSMutableA ...

  5. 【小梅哥SOPC学习笔记】系统时钟的使用

    给NIOS II CPU添加一颗澎湃的心——系统时钟的使用 本实验介绍如何在Qsys中添加一个定时器作为NIOS II的心跳定时器,并在NIOS II中软件编程使用该定时器. 将上一个实验watchd ...

  6. Inno Setup卸载时注销bho

    Inno setup是一个制作安装包的免费工具,比如你用Qt开发完成一款软件,拿Inno setup打个安装包甩给客户安装就好了. 但是bho插件在注册后,万一用户卸载软件时,bho插件还是躺在管理加 ...

  7. jenkins+docker+docker machine 远程部署

    dotnet publish -c Release docker build -t microtest:1.0 --build-arg microport=1000 -f "$WORKSPA ...

  8. Spring Boot - Spring Scheduling

    有时应用需要定时(如凌晨)执行一些任务(比如计算一些数据并存下来留给后续使用) 使用 使用@EnableScheduling注解启用Scheduling功能:不一定要标注在启动类上,也可以标注在@Co ...

  9. 数数(高维DP)

    T1 数数 [问题描述] fadbec 很善于数数,⽐如他会数将 a 个红球,b 个黄球,c 个蓝球,d 个绿球排成⼀列,任意相邻不同⾊的数⽬. 现在 R 君不知道 fadbec 数的对不对,想让你也 ...

  10. swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~

    title: swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~description: 阅读 sowft 框架源码, swoft 第一步, ...