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 }
vector标记

 

以上是关于ZOJ - 3715贪心的主要内容,如果未能解决你的问题,请参考以下文章

ZOJ 3689 Digging(贪心+dp)

zoj 3963 Heap Partition(贪心)

UVA10670 POJ1907 ZOJ2372 Work Reduction贪心

ZOJ4067 Books(贪心)

zoj 4120Tokens on the Segments(优先队列+贪心)

2017CCPC秦皇岛G ZOJ 3987Numbers(大数+贪心)