贪心算法小结

 

A

题意:多个教室经过走廊搬桌子,不能共用已被占用的走廊(不相交可以同时搬运),每次需要十分钟,问最少需要的时间。

思路:每次搬运都会覆盖一段走廊,会覆盖这段的点,找出所有点中覆盖次数最多的即是需要搬运的最大次数。

 

B

题意:O(-1)

思路:O(-1)。

 

C

题意:有n头牛在一条线上,每头牛都会嚎叫,为了让所有牛都听见,嚎叫的声音等于离它最远牛的距离,问所有牛嚎叫的声音分贝是多少。

思路:对所有牛按位置排序,分贝划过两头牛之间距离的次数之和便是答案,遍历即可。

 

D

题意:有n个人,每个人都有m张纸牌,所有的纸牌都在1~n*m之间并且不重复,每轮每个人拿出一张纸牌比较大小,最大的赢得这轮。给出你的m张纸牌大小,问你最小能赢多少轮。

思路:你从最小开始出,对方先出一张比你大的,其他人从最小开始出,依次继续。当你再次出牌的时候找不到对手点数有比你大的,那么你后面都是赢。

 

E

题意:给你n种品牌交流机器,每种类型交流机器又有m种分支产品,现在让你从n种品牌中各选择一种,要求B/P最大,B为这选择的n种中b最小的,P则为选择的n种的价值和。

思路:枚举所有出现的B,对每种产品的p进行从小到大排序,每次都选择这种产品中第一个大于B的。选取所有枚举情况的最优解即可。

 

F

题意:O(-1).

思路:不对局部而对全程分析,你跟到最后一起到达终点的必是在你后出发而又最快到达终点的。

 

G/H

题意:O(-1)

思路:两题类似。先对罚时从大到小排序,对于每门功课,从最后期限开始往前找(保证最优解),找到空位即可。

 

I

题意:给出海面上n个岛屿的坐标,给出你雷达扫描半径,问你最少要安装多少个雷达才可监控到所有的海上岛屿。

思路:对每个岛屿分析可知,每个岛屿可被地面上一段[l,r]内的雷达扫射到,只要雷达安装到这段区域内便可监控到该岛屿。处理出所有的这些区间段,排序后从左到右扫一遍,覆盖区域选最左边的右端点值rbd,在rbd左边的相交区域选一个雷达即可。

 

J

题意:O(-1)

思路:排序之后从左往右铺即可,要注意的一点是当木板很长很长的一种情况。

 

K

题意:O(-1).

思路:黑书上的一道例题。因为钓鱼只能从左往右走,枚举所有情况:即只走到第i个(i输出1~n)。然后对于枚举的每种情况,选择鱼最多的池塘去钓鱼,这时候你可以想象成你能飞来飞去。

 

L

题意:有一颗n个节点n-1条边的树,每个节点有一个C[i]值,每到达一个节点time加1,到达这个节点的处罚是time*C[i],并且只有当父亲节点走完了才能走孩子节点。

思路: 开始对C值进行排序,每次都找未标记的C值最大的节点,从该节点往前走到根节点都标记一下,后来证明这样是错的。

因为每个节点受限制于父亲节点,正确的处理方法是利用fact[i]/num[i]进行贪心操作,fact[i]表示该节点集合的C值总和,num表示该集合的节点数。每次选取fact[i]/num[i]最大的,并将它归并与父亲集合,父亲num值加1。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 typedef long long lld;
 8 const int maxn=1024;
 9 int pre[maxn], next[maxn][maxn], ind[maxn],  visit[maxn], fact[maxn], num[maxn];
10 int n, rt;
11 
12 int find()
13 {
14     double maxx=0, pos=-1;
15     for(int i=1; i<=n; i++)
16         if(!visit[i]&&i!=rt&&1.0*fact[i]/num[i]>maxx)
17         {
18             maxx=1.0*fact[i]/num[i];
19             pos=i;
20         }
21     return pos;
22 }
23 
24 void Union(int x, int y)
25 {
26     for(int i=1; i<=ind[x]; i++)
27     {
28         pre[ next[x][i] ]=y;
29         next[y][++ind[y]]=next[x][i];
30     }
31     fact[y]+=fact[x];
32     num[y]+=num[x];
33 }
34 
35 void Solve()
36 {
37     int ans=0;
38     for(int i=1; i<n; i++)
39     {
40         int id=find();
41         if(id==-1) break;
42         visit[id]=1;
43         ans+=fact[id]*num[ pre[id]  ];
44         Union(id,pre[id]);
45     }
46     cout << ans+fact[rt] <<endl;
47 }
48 
49 int main()
50 {
51       while(cin >> n >> rt, n+rt)
52       {
53           memset(visit,0,sizeof(visit));
54           memset(next,0,sizeof(next));
55           memset(ind,0,sizeof(ind));
56           for(int i=1; i<=n; i++)
57           {
58               scanf("%d",fact+i);
59               num[i]=1;
60           }
61           for(int i=1; i<=n-1; i++)
62           {
63               int u, v;
64               scanf("%d%d",&u,&v);
65               pre[v]=u;
66               next[u][++ind[u]]=v;
67           }
68           Solve();
69       }
70 }
View Code

 

M

题意:O(-1)

思路:从大到小,三个一组,所有组里面最小的之和即使答案。

 

 

posted @ 2013-08-03 18:20  Mr. Ant  阅读(538)  评论(0编辑  收藏  举报