POJ1716 贪心

题目大意:在[0,10000]上给出n个区间,要求在区间选整数点,每个区间至少包含两个点,问至少要几个点。题目保证有解决方案。

题目分析:

  我们做过在区间上至少包含一个点的题目。类似的方法,我们先排序后去掉区间包含的情况。接着我们贪心。对于第i个区间,取最后两个点,如果第i+1个区间包含这两个点,那么跳到第i+2个区间。如果第i+1个区间一个点也不包括,那么对于第i+1个区间取最后两个点。如果只包含一个点,那么在第i+1个区间取最后一个点,继续判断。

题目代码:

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<queue>
 6 #include<vector>
 7 #include<algorithm>
 8 using namespace std;
 9 
10 struct edge{int to,w;};
11 
12 int n;
13 vector <edge> g[10200];
14 int d[10200];
15 queue<int> que;
16 int maxx;
17 
18 void read(){
19     for(int i=0;i<=10001;i++) g[i].clear();
20     maxx = -1200;
21     for(int i=1;i<=n;i++){
22         int x,y; scanf("%d%d",&x,&y);
23         maxx = max(maxx,y+1);
24         x++;y++;
25         edge ed;ed.to = y;ed.w = 2;
26         g[x-1].push_back(ed);
27     }
28     for(int i=0;i<=maxx;i++){
29         edge ed;ed.to=i+1;ed.w=0;
30         g[i].push_back(ed);
31         ed.to=i;ed.w=-1;
32         g[i+1].push_back(ed);
33     }
34 }
35 
36 void work(){
37     for(int i=1;i<=maxx;i++) d[i]=-1;
38     que.push(0);
39     d[0] = 0;
40     while(!que.empty()){
41         int k = que.front();que.pop(); 
42         for(int i=0;i<g[k].size();i++){
43             if(g[k][i].w+d[k] > d[g[k][i].to]){
44                 d[g[k][i].to] = g[k][i].w + d[k];
45                 que.push(g[k][i].to);
46             }
47         }
48     }
49     printf("%d
",d[maxx]);
50 }
51 
52 int main(){
53     scanf("%d",&n);
54     read();
55     work();
56     return 0;
57 }

思考:我们不妨对问题加以拓展。

  问题一:我们做过一个区间选一个点的题,做过一个区间选两个点的题。那么当一个区间选n个点时怎么去做?

  问题二:上面的区间选点数量都是相同的,当区间选点数量不同时怎么做?

解法:

  对于问题一:很容易就能想出拓展方法,每次对每个区间都选最后n个点,容易证明这是最优的。

  对于问题二:发现上面的贪心无法使用,需要另辟蹊径。不妨令s[i]表示前i个点被选的情况。那么有s[r]-s[l-1]>=c[i]。c[i]该区间应选点数。

        由于这里有很多个不等式,又要求最小化s[10000],容易思考到这可能是要用到线性规划去解决。

        接着我们打了一个单纯形法。

        

        收获了一个TLE。仔细想想就会发现问题并不是这么难。这里的不等式并不如线性规划里面的那么复杂。

        那么我们可以建图跑最长路。这就是答案。具体怎么建图可以参考网上其它人的博客。我不想再写下去了。

原文地址:https://www.cnblogs.com/1-1-1-1/p/7608044.html