hdu 1050 Moving Tables(迷之贪心...)

  题意:有400间房间按题目中图片所给的方式排列,然后给出要移动的n张桌子所要移动的范围,每张桌子要移动的范围不能出现重叠的区域;问最少要多少次才能移动完所有的桌子。

  题解思路:把题目转换下,就是有n个区间,每次可以去除掉k个没有重叠部分的区间,最少要多少次能去掉所有区间。妥妥的,,贪心。可能会有人联想到经典的“区间调度问题”。但很遗憾,在这里行不通;区间调度问题是按区间右端排序后尽可能选取结束时间早的,但这种贪心只是一次性选取尽可能多的区间,而本题是要求选取完所有区间所要花费次数最少。从整体上看,如果只是每次找到尽可能多的区间,对一次的遍历从房间尾号排序确实达到了这样的目的,但整体目的却不是这样的,因为最终是要把所有的区间都找完的,并不是说仅仅找最多的一次,你还要顾及后面的让每一次都尽可能找得更多的房间。所以不管前几次怎样,你现在要找的这一次需要越靠前开始找。 因此正解应该是按区间左端排序,然后每次找最靠前的。 虽然看完上面的解释可能还是会不怎么明白为什么第一种贪心是错的,那就测试下面这组数据琢磨琢磨吧:

 1 Input
 2 1
 3 5
 4 2 10
 5 6 14
 6 12 20
 7 16 18
 8 30 40
 9 
10 Output
11 20

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <set>
 7 #include <utility>
 8 #include <vector>
 9 #include <map>
10 #include <queue>
11 #include <stack>
12 const int inf=0x3f3f3f3f;
13 const double PI=acos(-1.0);
14 const double EPS=1e-10;
15 using namespace std;
16 typedef long long ll;
17 typedef pair<int,int> P;
18 
19 int T,n;
20 typedef struct node
21 {
22     int l,r;
23 } node;
24 node a[205];
25 bool cmp(node a,node b)
26 {
27     return a.l<b.l;
28 }
29 int book[205];
30 int main()
31 {
32     //freopen("input.txt","r",stdin);
33     scanf("%d",&T);
34     while(T--)
35     {
36         scanf("%d",&n);
37         int l,r;
38         for(int i=1; i<=n; i++)
39         {
40             scanf("%d%d",&l,&r);
41             a[i].l=(l%2)?(l/2+1):l/2;
42             a[i].r=(r%2)?(r/2+1):r/2;
43             if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
44         }
45         //
46         sort(a+1,a+1+n,cmp);
47         //
48         memset(book,0,sizeof(book));
49         int ans=0;
50         int N=n;
51         while(n)
52         {
53             //printf("%d\n",n);
54             ans++;
55             int temp=1;
56             while(book[temp]) temp++;
57             book[temp]=1;
58             n--;
59             for(int i=temp+1; i<=N; i++)
60             {
61                 if(!book[i]&&a[i].l>a[temp].r)
62                 {
63                     n--;
64                     book[i]=1;
65                     temp=i;
66                 }
67             }
68         }
69         //
70         printf("%d\n",ans*10);
71     }
72     return 0;
73 }

   还有另一种贪心方法更直接明了:计算出所有区间中最大的重叠次数,即答案。因为假设有块地方被k个区间所重叠,那么无论如何选择,这块地方肯定都是至少要k次才能移动完重叠在这上面的区间;而其他地方肯定也都能在k次以内移动完的。 计算重叠部分的话,,这题数据略水可以暴力过去...=_=

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <set>
 7 #include <utility>
 8 #include <vector>
 9 #include <map>
10 #include <queue>
11 #include <stack>
12 const int inf=0x3f3f3f3f;
13 const double PI=acos(-1.0);
14 const double EPS=1e-10;
15 using namespace std;
16 typedef long long ll;
17 typedef pair<int,int> P;
18 
19 int T,n;
20 typedef struct node
21 {
22     int l,r;
23 } node;
24 node a[205];
25 int book[205];
26 int main()
27 {
28     //freopen("input.txt","r",stdin);
29     scanf("%d",&T);
30     while(T--)
31     {
32         memset(book,0,sizeof(book));
33         scanf("%d",&n);
34         int l,r;
35         for(int i=1; i<=n; i++)
36         {
37             scanf("%d%d",&l,&r);
38             a[i].l=(l%2)?(l/2+1):l/2;
39             a[i].r=(r%2)?(r/2+1):r/2;
40             //
41             if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
42             //
43             for(int j=a[i].l;j<=a[i].r;j++) book[j]++;
44 
45         }
46         int Max=-inf;
47         for(int i=1;i<=200;i++) Max=max(Max,book[i]);
48         printf("%d\n",Max*10);
49     }
50     return 0;
51 }

 

posted @ 2017-03-06 10:50  爱喝可乐的咖啡  阅读(213)  评论(0编辑  收藏  举报