Allowance POJ 3040(贪心)
原题
题目分析
有点难码的贪心题,策略是先能用大面额的就用大面额,然后凑出的价格不要高于c,如果凑到最后不能刚好凑完c,则能用小面额补就用小面额补,目的是让凑出的价格尽可能接近c,这样能少浪费钱,具体实现就是先从现有硬币里按照上述规则找一套凑法,然后不断用这个凑法凑直到硬币不足为止,接着又从剩下的硬币中选出一种凑法继续同样的操作.注意有一点可以优化,如果有面额大于c的货币,直接统计到答案中,因为不需要凑.
代码
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <algorithm> 5 #include <utility> 6 #include <ctime> 7 #include <cmath> 8 #include <cstring> 9 #include <string> 10 #include <stack> 11 #include <queue> 12 #include <vector> 13 #include <set> 14 #include <map> 15 16 using namespace std; 17 typedef long long LL; 18 const int INF_INT=0x3f3f3f3f; 19 const LL INF_LL=0x3f3f3f3f3f3f3f3f; 20 21 typedef pair<int,int> P; 22 int N,C; 23 P coin[20]; 24 int cnt; 25 int ans; 26 27 void solve() 28 { 29 for(int i=cnt-1;i>=0;i--) 30 { 31 while(coin[i].second) 32 { 33 int cost[20],rest=C; 34 for(int j=0;j<cnt;j++) cost[j]=0; 35 int k=i; 36 while(rest>0&&k>=0) 37 { 38 while(coin[k].second&&rest>=coin[k].first) rest-=coin[k].first,coin[k].second--,cost[k]++; 39 k--; 40 } 41 k=0; 42 while(rest>0&&k<=i) 43 { 44 while(coin[k].second&&rest>0) rest-=coin[k].first,coin[k].second--,cost[k]++; 45 k++; 46 } 47 if(rest>0) return; 48 else 49 { 50 ans++; 51 int minn=INF_INT; 52 for(int j=0;j<cnt;j++) 53 if(cost[j]) minn=min(minn,coin[j].second/cost[j]); 54 ans+=minn; 55 for(int j=0;j<cnt;j++) 56 if(cost[j]) coin[j].second-=minn*cost[j]; 57 } 58 /* 59 printf("ans=%d\n",ans); 60 for(int j=0;j<cnt;j++) 61 printf("%d %d\n",coin[j].first,coin[j].second);*/ 62 } 63 } 64 return ; 65 } 66 67 int main() 68 { 69 // freopen("black.in","r",stdin); 70 // freopen("black.out","w",stdout); 71 scanf("%d %d",&N,&C); 72 73 for(int i=0;i<N;i++) 74 { 75 int x,y; 76 scanf("%d %d",&x,&y); 77 if(x>=C) ans+=y; 78 else coin[cnt].first=x,coin[cnt++].second=y; 79 } 80 sort(coin,coin+cnt); 81 solve(); 82 cout<<ans<<endl; 83 return 0; 84 }