您的位置:首页 > 其它

HDU 3348 By Assassin [可怕的模拟题]

2017-05-02 10:36 375 查看

题意

有1角,5角,1元,5元、十元的纸币,每种硬币现有总数已知,想要正好组合出p角,问最多最少分别用多少张纸币,如果不能组合成功,输出“-1 -1”.

分析

思路是直接了当的,首先我们先求使用张数最小的情况,注意每种纸币需要判断现有的数量是否够用,如果最小值可以求的,那么最大值一定存在,否则输出-1 -1.
那么我们求得最小值的每种纸币的张数之后呢,我们想,如何让张数尽可能变多?100=50+50 50=10*5 10=5*2 5=1*5 .只要转换,就可实现张数的变多。还是注意每次注意判断每种纸币剩余张数


坑点来了!纸币的转换不一定只是转换成单一种类,比如说100=50+10*2+5*4+1*10

那么这个就很麻烦了…我的处理方法如下,假设数组从1-5分别代表100、50、10、5、1。假设我们想转换的面值位置为i,那么

1.先尝试换i之后位置面值的某一种,比如100=50*2=10*10=5*20=1*100

2.用贪心将i位置面值,转换成i之后面值的组合。如果能转换,则转换,不能拉到。我们考虑极限情况,可能出现剩下50*1、10*9、5*19、1*99,也就是说当前i可以再转换的次数不一定只有1次,没关系,我们while循环多搞几次即可!

实现比较复杂,我的代码也比较难看,尽量用注释说明

#include<bits/stdc++.h>
using namespace std;
long long p,a1,a5,a10,a50,a100;
long long has[6];                   //代表某面值纸币有多少张
long long value[6]={0};             //最大最小张数计算中每种面值使用的张数
int price[6]={0,100,50,10,5,1};     //纸币的面额
long long maxx,minn;
int main(){
int t;
scanf("%d",&t);
while(t--){
//scanf("%lld%lld%lld%lld%lld%lld",&p,&a1,&a5,&a10,&a50,&a100);
scanf("%lld%lld%lld%lld%lld%lld",&p,&has[5],&has[4],&has[3],&has[2],&has[1]);
long long temp=p;           //先找到用张数最少的情况
value[1]=temp/100;
if(value[1]>has[1]){        //注意每次求的时候考虑面额最多张数
value[1]=has[1];
temp-=100*has[1];
}
else {
temp%=100;
}

value[2]=temp/50;
if(value[2]>has[2]){
value[2]=has[2];
temp-=50*has[2];
}
else {
temp%=50;
}

value[3]=temp/10;
if(value[3]>has[3]){
value[3]=has[3];
temp-=10*has[3];
}
else {
temp%=10;
}

value[4]=temp/5;
if(value[4]>has[4]){
value[4]=has[4];
temp-=5*has[4];
}
else {
temp%=5;
}

value[5]=temp;
if(value[5]>has[5]){
value[5]=has[5];
temp-=1*has[5];
}
else {
temp%=1;
}
if(temp==0){            //如果我们 temp用光了,说明可以正好转换
minn=value[1]+value[2]+value[3]+value[4]+value[5];
}
else {
cout<<-1<<" "<<-1<<endl;
continue;
}
//cout<<value[1]<<" "<<value[2]<<" "<<value[3]<<" "<<value[4]<<" "<<value[5]<<endl;
long long temp1,temp2;
for(int i=1;i<5;i++){
for(int j=i+1;j<=5;j++){        //和i以后的每一个面额的转换
temp1=has[j]-value[j];      //i位置面额可以转换多少张
temp2=temp1/(price[i]/price[j]);    //转换成j位置面额可以有多少张
if(value[i]>temp2){
value[i]-=temp2;
value[j]+=temp2*(price[i]/price[j]);
}
else{
value[j]+=value[i]* (price[i]/price[j]);
value[i]=0;
}
}
int ttt=10;         //多循环几次找出i位置转换成不同面额组合的不同情况
if(value[i]>0){
while(ttt--&&value[i]>0){       //当使用的i面额没有了跳出
int use[6]={0};             //记录转换使用的张数,如果转换成功了,需要用use和value更新
int target=price[i];        //转换的目标值
long long temp4;
for(int k=i+1;k<=5;k++){
temp4=target/price[k];  //剩余值可以转换成k的张数
if(temp4>has[k]-value[k]){
target-=(has[k]-value[k])*price[k];
use[k]=has[k]-value[k];
}
else {
use[k]+=temp4;
target-=temp4*price[k];
}
if(target==0){          //如果转换成功
value[i]--;
for(int kk=1;kk<=5;kk++){   //更新状态值
value[kk]+=use[kk];
}
break;
}
}
}
}
//cout<<value[1]<<" "<<value[2]<<" "<<value[3]<<" "<<value[4]<<" "<<value[5]<<endl;
}
maxx=value[1]+value[2]+value[3]+value[4]+value[5];
cout<<minn<<" "<<maxx<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: