ZOJ - 3715贪心
Posted lmcc1108
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ - 3715贪心相关的知识,希望对你有一定的参考价值。
ZOJ - 3715KindergartenElection
题目大意:幼儿园里正在举办班长选举,除1号小朋友外每个人都会投他最好的朋友,但1号小朋友可以贿赂别人(小伙子有丶想法),被贿赂的小朋友就会把票投给1号小朋友而不是他最好的朋友,对于不同的小朋友贿赂的花费也不同,1号小朋友想要自己是唯一的班长(票数最高),问他最少需要花费多少糖果?
由题目来想,很容易想到贪心,但是不知道怎么贪心。如果是简单让1号是票数最高的小朋友,他每次贿赂都有两种选择,一种是贿赂花费小的人来投他,另一种是贿赂票数比他高的小朋友的投票者中花费小的,如果这两种情况是同一个人的话,那还好说,但如果不是的话,那就不好判断了。所以我们转换思路,我们枚举1号小朋友能得到的票数为x,那么其他小朋友的票数应该小于x,否则1号小朋友应该贿赂他的投票者中一部分花费小的来让他的票数小于x,而如果那一部分贿赂完后,如果1号小朋友的票数大于x,那说明x这个票数是不合理的,1号小朋友应该得到多于x的票才能唯一最多票。而如果还不够x应该在剩下的小朋友里贿赂花费小的来达到x,然后更新答案。
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 priority_queue<int,vector<int>,greater<int> > q[118],p,temp;//由小到大的优先队列 5 int fri[118]; 6 int main() 7 { 8 int t,n,x; 9 scanf("%d",&t); 10 while(t--) 11 { 12 scanf("%d",&n); 13 while(q[1].size())//每次要先把队列清空 14 q[1].pop(); 15 for(int i=2;i<=n;i++) 16 { 17 while(q[i].size()) 18 q[i].pop(); 19 scanf("%d",&fri[i]); 20 } 21 for(int i=2;i<=n;i++) 22 { 23 scanf("%d",&x); 24 q[fri[i]].push(x); 25 } 26 int ans=0x3f3f3f3f; 27 //1号小朋友能得到的票数范围就是已经有的票数到n-1票数 28 for(int i=q[1].size();i<=n-1;i++) 29 { 30 int cost=0,num=0; 31 while(p.size()) 32 p.pop();//p储存没有被贿赂的小朋友 33 for(int j=2;j<=n;j++) 34 { 35 temp=q[j]; 36 //如果这位小朋友的票数大于等于i那么应该把多的先贿赂了 37 while(temp.size()>=i&&temp.size()) 38 { 39 num++; 40 cost+=temp.top(); 41 temp.pop(); 42 } 43 //剩下的储存到没被贿赂的小朋友里 44 while(temp.size()) 45 { 46 p.push(temp.top()); 47 temp.pop(); 48 } 49 } 50 //如果当前的票数还没达到i则补够 51 while(q[1].size()+num<i&&p.size()) 52 { 53 num++; 54 cost+=p.top(); 55 p.pop(); 56 } 57 //当好等于i说明i这个答案合理 58 if(q[1].size()+num==i&&cost<ans) 59 ans=cost; 60 } 61 printf("%d\n",ans); 62 } 63 return 0; 64 }
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 vector<int> v[118],vv; 7 int fri[118],cdy[118],book[118]; 8 bool cmp(const int &a,const int &b){ 9 return cdy[a]<cdy[b]; 10 }//按贿赂的糖果数由小到大排 11 int main() 12 { 13 int t,n,x; 14 scanf("%d",&t); 15 while(t--) 16 { 17 scanf("%d",&n); 18 vv.clear(); 19 v[1].clear(); 20 for(int i=2;i<=n;i++) 21 { 22 v[i].clear(); 23 book[i]=0; 24 scanf("%d",&fri[i]); 25 } 26 for(int i=2;i<=n;i++) 27 { 28 scanf("%d",&cdy[i]); 29 v[fri[i]].push_back(i); 30 if(fri[i]!=1)//vv储存没有把票投给1号小朋友的小朋友 31 vv.push_back(i); 32 } 33 //因为贪心嘛,都先按花费由小到大排 34 sort(vv.begin(),vv.end(),cmp); 35 for(int i=2;i<=n;i++) 36 sort(v[i].begin(),v[i].end(),cmp); 37 int ans=0x3f3f3f3f; 38 for(int i=v[1].size();i<=n;i++) 39 { 40 int cost=0,num=0; 41 memset(book,0,sizeof(book)); 42 for(int j=2;j<=n;j++) 43 if(v[j].size()>=i) 44 for(int k=0;k<v[j].size()-i+1&&k<v[j].size();k++) 45 { 46 cost+=cdy[v[j][k]]; 47 book[v[j][k]]=1; 48 num++; 49 }//多于i的部分先贿赂掉,并标记已经贿赂过了 50 for(int j=0;j<vv.size()&&num+v[1].size()<i;j++) 51 { 52 if(book[vv[j]]) 53 continue; 54 cost+=cdy[vv[j]]; 55 num++; 56 } 57 if(num+v[1].size()==i&&cost<ans) 58 ans=cost; 59 } 60 printf("%d\n",ans); 61 } 62 return 0; 63 }
以上是关于ZOJ - 3715贪心的主要内容,如果未能解决你的问题,请参考以下文章
UVA10670 POJ1907 ZOJ2372 Work Reduction贪心