题意:
现在你有P元钱,有10种不同面值的硬币,每种硬币有一定的数量,求用尽量多的硬币凑出P元钱,如果凑不出输出“-1”。
题解:
- 一、贪心(反向)
(可以看下:一位大佬十分详细的题解)
反向:求出所有硬币的总价值(sum)- 所求的价值(P),问题转化成用尽可能少的硬币去凑出这个差值(sum-P);
贪心思想:从面值大的硬币开始,尽可能多地使用大面值硬币;
算法核心:因为(2050)和(200
500)不是整数倍的关系,所以不能直接贪心,那么就需要转化问题;当取偶数个50,可以用20拼凑出来,但取奇数个50时,用20是拼凑不出来的。
我们可以枚举以下四种情况:
(50和500都是偶数个,不先取50和500)
(50为奇数个,500为偶数个,即我们先取一个50)
(50为偶数个,500为奇数个,即我们先取一个500)
(50为奇数个,500为奇数个,即我们先取一个50和一个500)
之后对于50和500都成对地取,每次取50或500的时候就取偶数个。然后就可以用贪心了。#include <set> #include <map> #include <cmath> #include <stack> #include <queue> #include <vector> #include <string> #include <cstdio> #include <cstring> #include <sstream> #include <iomanip> #include <iostream> #include <algorithm> #define clr(str,x) memset(str,x,sizeof(str)) #define FRER() freopen("in.txt","r",stdin); #define FREW() freopen("out.txt","w",stdout); #define INF 0x7fffffff #define maxn typedef long long int ll; using namespace std; int have[12],c[12],val[10]= {1,5,10,20,50,100,200,500,1000,2000}; int consthave[12]; int solve(int t) { int ans=0; for(int i=9; i>=0; i--) { if(i==4||i==7) { int temp = min(t/(2*val[i]),have[i]/2); ans += temp*2; t -= val[i] * 2 * temp; } else { int temp = min(t/val[i],have[i]); ans += temp; t -= val[i] * temp; } if(t==0) break; } if(t>0) return INF; else return ans; } int main() { //FRER() //FREW() int T,p; scanf("%d",&T); while(T--) { int sum=0,tol=0; scanf("%d",&p); for(int i=0; i<10; i++) { scanf("%d",&consthave[i]); sum+=consthave[i]*val[i]; tol+=consthave[i]; } sum-=p; if(sum<0) { printf("-1\n"); continue; } int ans = INF; for(int i=0; i<2; i++) { for(int j=0; j<2; j++) { memcpy(have,consthave,sizeof(consthave)); int t=sum; if(i) { if(have[4]) t-=50,have[4]--; else continue; } if(j) { if(have[7]) t-=500,have[7]--; else continue; } if(t>=0) ans=min(ans,solve(t)+i+j); } } if(ans==INF) printf("-1\n"); else printf("%d\n",tol-ans); } return 0; }
第二种贪心做法,有点类似搜索。
#include <set> #include <map> #include <cmath> #include <stack> #include <queue> #include <vector> #include <string> #include <cstdio> #include <cstring> #include <sstream> #include <iomanip> #include <iostream> #include <algorithm> #define clr(str,x) memset(str,x,sizeof(str)) #define FRER() freopen("in.txt","r",stdin); #define FREW() freopen("out.txt","w",stdout); #define INF 0x3f3f3f3f #define maxn typedef long long int ll; using namespace std; int have[10],val[]= {1,5,10,20,50,100,200,500,1000,2000}; int consthave[10]; int solve(int t) { int ans=0; for(int i=9; i>=0; i--) { if(i==4||i==7) { int temp = min(t/(val[i]*2),have[i]/2); ans += temp*2; t -= val[i] * 2 * temp; } else { int temp = min(t/val[i],have[i]); ans += temp; t -= val[i] * temp; } if(t==0) break; } if(t>0) return INF; else return ans; } int main() { //FRER() //FREW() int T,p; scanf("%d",&T); while(T--) { int sum=0,tol=0; scanf("%d",&p); for(int i=0; i<10; i++) { scanf("%d",&consthave[i]); sum+=consthave[i]*val[i]; tol+=consthave[i]; } sum-=p; if(sum<0) { printf("-1\n"); continue; } int ans = INF; for(int i=0; i<2; i++) { for(int j=0; j<2; j++) { memcpy(have,consthave,sizeof(consthave)); int t=sum; if(i) { if(have[4]) t-=50,have[4]--; else continue; } if(j) { if(have[7]) t-=500,have[7]--; else continue; } if(t>=0) ans=min(ans,solve(t)+i+j); } } if(ans==INF) printf("-1\n"); else printf("%d\n",tol-ans); } return 0; }