贪心专题(不定期更新)

1、UVa 10382 - Watering Grass (贪心—区间覆盖)

  题意:一块矩形草坪,给出若干个分布在中轴线上的喷水装置,喷水范围为圆形。问能否覆盖整个草坪,若能,求出最少的喷水装置数目。

  思路:圆形半径小于等于草坪宽度一半的不用考虑;在剩下的喷水圆形区域中,求出对应覆盖草坪的矩形区块,之后则进行贪心处理:找出矩形区块[L,R]左侧L小于等于当前已覆盖区域的右侧POS的区块中,右侧R最大的那个,同时更新POS.

  

 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 struct sprk
 6 {
 7     double r,ldis;
 8     double L, R;
 9 }v[10005];
10 double n, l, w;
11 bool Cmp(const sprk& a, const sprk& b)
12 {
13     if (a.L < b.L) return true;
14     else if (a.L == b.L)
15     {
16         if (a.R < b.R) return true;
17         else return false;
18     }
19     else return false;
20 }
21 int main()
22 {
23     while (cin >> n >> l >> w)
24     {
25         int sz = 0;
26         sprk tmp;
27         for (int i = 0; i < n; i++)
28         {
29             cin >> tmp.ldis >> tmp.r;
30             if (tmp.r <=w/2.0) continue;
31             double tl = sqrt(tmp.r*tmp.r-w*w/4.0);
32             tmp.L = tmp.ldis*1.0 - tl;
33             tmp.R = tmp.ldis*1.0 + tl;
34             if (tmp.R < 0) continue;
35             v[sz++] = tmp;
36         }
37         sort(v, v+sz, Cmp);
38         int num = 0;
39         double pos = 0;
40         int k = 0;
41         bool ok = false;
42         if (sz>0&&v[0].L <= 0)
43         {
44             k = 0;
45             pos = 0;
46             while (k < sz)
47             {
48                 int j = k;
49                 double Rpos = pos;
50                 while (j < sz&&v[j].L <= pos)
51                 {
52                     if (v[j].R > Rpos) Rpos = v[j].R;
53                     ++j;
54                 }
55                 if (j == k)break;
56                 num++;
57                 pos = Rpos;
58                 k = j;
59                 if (pos >= l)
60                 {
61                     ok = true;
62                     break;
63                 }
64             }
65         }
66         if(ok) cout << num << endl;
67         else cout << -1 << endl;
68     }
69     return 0;
70 }
View Code

2、Uva10905 Children's Game

  题意:给出若干个数字,把这些数字重新组合成一个新的数字,要求这个数字的字典序最大。

  思路:用字符串保存;从大到小排序,关键为比较函数:把两个字符串按先后顺序重新组合成两个新的字符串,比较两个新字符串的字典序大小,字典序大的新字符串的第一个子字符串如果是传入比较函数的第一个参数,则为true,否则为false。

 1 #include<iostream>
 2 #include<string>
 3 #include<string.h>
 4 #include<algorithm>
 5 using namespace std;
 6 string s[55];
 7 int n;
 8 bool Cmp(const string &a, const string &b)
 9 {
10     string tmp1 = a + b;
11     string tmp2 = b + a;
12     if (tmp1 > tmp2) return true;
13     else return false;
14 }
15 int main()
16 {
17     while (cin >> n, n != 0)
18     {
19         for (int i = 0; i < n; i++) cin >> s[i];
20         sort(s, s + n, Cmp);
21         for (int i = 0; i < n; i++)
22         {
23             cout << s[i];
24         }
25         cout << endl;
26     }
27     return 0;
28 }
View Code

3、UVA 11134 Fabled Rooks

  题意:给出n*n的棋盘,以及n个棋子的限制放置的矩形区域(给出左上顶点(xl,yl)和右下顶点的坐标(xr,yr))。要求每行每列只能有一个棋子。求任意一种方案,若无,则输出impossible

  思路:分别对行和列进行贪心处理,贪心过程和第一题相似:对于行r(列c),找到xl≤r,xr≥r(ylc,yr≥c)且未被选取的棋子中,xr(yr)最小的那个,使其x(y)坐标为r(c).

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<memory.h>
 4 using namespace std;
 5 const int maxn = 5005;
 6 struct node
 7 {
 8     int id;
 9     int xl, yl, xr, yr;
10     int x, y;
11 }ch[maxn];
12 bool vis[maxn];
13 int n;
14 bool flag = true;
15 void CalX()
16 {
17     memset(vis, 0, sizeof(vis));
18     int r = 1;
19     for (int i = 0; i < n; i++)
20     {
21         int minr = maxn;
22         int pos;
23         for (int j = 0; j < n; j++)
24         {
25             if (!vis[j] && ch[j].xl <= r&&ch[j].xr >= r&&ch[j].xr < minr)
26             {
27                 minr = ch[j].xr;
28                 pos = j;
29             }
30         }
31         if (minr == maxn)
32         {
33             flag = false;
34             return;
35         }
36         vis[pos] = true;
37         ch[pos].x = r;
38         r++;
39     }
40 }
41 void CalY()
42 {
43     memset(vis, 0, sizeof(vis));
44     int c = 1;
45     for (int i = 0; i < n; i++)
46     {
47         int minc = maxn;
48         int pos;
49         for (int j = 0; j < n; j++)
50         {
51             if (!vis[j] && ch[j].yl <= c&&ch[j].yr >= c&&ch[j].yr < minc)
52             {
53                 minc = ch[j].yr;
54                 pos = j;
55             }
56         }
57         if (minc == maxn)
58         {
59             flag = false;
60             return;
61         }
62         vis[pos] = true;
63         ch[pos].y = c;
64         c++;
65     }
66 }
67 int main()
68 {
69     while (cin >> n, n != 0)
70     {
71         flag = true;
72         for (int i = 0; i < n; i++)
73         {
74             cin >> ch[i].xl >> ch[i].yl >> ch[i].xr >> ch[i].yr;
75             ch[i].id = i + 1;
76         }
77         CalX();
78         if(flag) CalY();
79         if (flag)
80         {
81             for (int i = 0; i < n; i++)
82             {
83                 cout << ch[i].x << ' ' << ch[i].y << endl;
84             }
85         }
86         else cout << "IMPOSSIBLE
";
87     }
88     return 0;
89 }
View Code

4、poj 3045 Cow Acrobats(贪心, 二分) 

  题意:有n头牛,每头牛有其重量wi,力气si.将这些牛叠罗汉,每头牛都有一定的风险使整个叠罗汉崩塌,风险值为其上面牛的总重减去该牛的力气。求在所有种叠罗汉的顺序中,最小的风险值。

  思路:先考虑最底下一头牛,设其风险值为(sum+w1)-(w1+s1),因为如果把其换成其他牛,sum+w1不变,但w1+s1有变。所以贪心地处理,wi+si大的放下面;然后考虑剩下的n-1头牛,该哪头放在从底向上的第二个位置呢?同理,可知把这n-1头牛中wi+si最大的放在该位置。其他类似

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn = 50005;
 5 struct Cow
 6 {
 7     int w;
 8     int s;
 9 }cows[maxn];
10 
11 bool Cmp(const Cow&a, const Cow&b)
12 {
13     if (a.s + a.w > b.s + b.w)  return true;
14     else if (a.s + a.w == b.s + b.w) return a.s > b.s;
15     else return false;
16 }
17 
18 int n;
19 int main()
20 {
21     while (cin >> n)
22     {
23         for (int i = 0; i < n; i++) cin >> cows[i].w >> cows[i].s;
24         sort(cows, cows + n, Cmp);
25         long long risk = 0 - cows[n - 1].s;
26         long long ans = risk;
27         for (int i = n - 2; i >= 0; i--)
28         {
29             risk = risk + cows[i + 1].w + cows[i + 1].s - cows[i].s;
30             ans = max(ans, risk);
31         }
32         printf("%lld
", ans);
33     }
34     return 0;
35 }
View Code

 5、hdu 1789 Doing Homework again

  题意:需要完成n种功课,每种都有自己的截止日期和迟交的扣去的学分。假设完成一门功课的时间为1天。问最少会扣多少学分。

  思路:贪心处理,先按照截止日期大的排序,每次从其截止日前往前找第一个空闲的日子做该作业,如果找不到,只能扣学分。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<memory.h>
 4 #include<cstdio>
 5 using namespace std;
 6 const int maxn = 1010;
 7 struct node
 8 {
 9     int dscore;
10     int deadline;
11 }homeworks[maxn];
12 bool Cmp(const node&a, const node&b)
13 {
14     if (a.dscore == b.dscore) return a.deadline < b.deadline;
15     else return a.dscore > b.dscore;
16 }
17 
18 bool vis[maxn];
19 int main()
20 {
21     int t;
22     scanf("%d", &t);
23     while (t--)
24     {
25         int n;
26         scanf("%d", &n);
27         for (int i = 0; i < n; i++) scanf("%d", &homeworks[i].deadline);
28         for (int i = 0; i < n; i++) scanf("%d", &homeworks[i].dscore);
29         sort(homeworks, homeworks + n, Cmp);
30         memset(vis, 0, sizeof(vis));
31         int sum = 0;
32         for (int i = 0; i < n; i++)
33         {
34             int t = homeworks[i].deadline;
35             int j;
36             for (j = t; j >= 1; --j)
37             {
38                 if (!vis[j])
39                 {
40                     vis[j] = true;
41                     break;
42                 }
43             }
44             if (j < 1) sum += homeworks[i].dscore;
45         }
46         printf("%d
", sum);
47     }
48     return 0;
49 }
View Code

 6、hdu 1257 最少拦截系统

  题意:每个拦截系统的第一发能够达到任意高度,但之后的拦截导弹的高度不能超过之前的。现在有一大批导弹袭来,问最少的拦截系统个数。

  思路:如果当前所有拦截系统可到达的高度都不能拦截该导弹,则新增一个拦截系统,高度为该导弹的高度;否则,选择当前拦截系统中高度大于等于该导弹高度的最小的那个去拦截。

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn = 10010;
 5 const int INF = 0x7fffffff;
 6 int sys[maxn];
 7 int main()
 8 {
 9     int n;
10     while (~scanf("%d", &n))
11     {
12         int cnt = 0;
13         for (int i = 1; i <= n; i++)
14         {
15             int h;
16             scanf("%d", &h);
17             bool flag = false;
18             int pos = 0;
19             int mindis = INF;
20             for (int i = 0; i < cnt; i++)
21             {
22                 if (sys[i] >= h)//找到当前拦截系统高度与导弹高度最接近的去拦截
23                 {
24                     if (sys[i] - h < mindis)
25                     {
26                         mindis = sys[i] - h;
27                         pos = i;
28                         flag = true;
29                     }
30                 }
31             }
32             if (flag) sys[pos] = h;
33             else
34             {
35                 sys[cnt++] = h;
36             }
37         }
38         printf("%d
", cnt);
39     }
40     return 0;
41 }
View Code
原文地址:https://www.cnblogs.com/ivan-count/p/7208689.html