POJ 2168 Joke with Turtles(DP)

Description

There is a famous joke-riddle for children: 
Three turtles are crawling along a road. One turtle says: "There are two turtles ahead of me."  The other turtle says: "There are two turtles behind me." The third turtle says: "There are  two turtles ahead of me and two turtles behind me." How could this have happened?  The answer is -- the third turtle is lying!
Now in this problem you have n turtles crawling along a road. Some of them are crawling in a group, so that they do not see members of their group neither ahead nor behind them. Each turtle makes a statement of the form: "There are ai turtles crawling ahead of me and bi turtles crawling behind me." Your task is to find the minimal number of turtles that must be lying.  Let us formalize this task. Turtle i has xi coordinate. Some turtles may have the same coordinate. Turtle i tells the truth if and only if ai is the number of turtles such that xj > xi and bi is the number of turtles such that xj < xi. Otherwise, turtle i is lying.

Input

The first line of the input contains integer number n (1 <= n <= 1000). It is followed by n lines containing numbers ai and bi (0 <= ai, bi <= 1000) that describe statements of each turtle for i from 1 to n.

Output

On the first line of the output file write an integer number m -- the minimal number of turtles that must be lying, followed by m integers -- turtles that are lying. Turtles can be printed in any order. If there are different sets of m lying turtles, then print any of them.

题目大意:有n只乌龟,把他们放到一个数轴上(每个点可以放多只乌龟)。然后每只乌龟会告诉你它前面有多少只乌龟后面有多少只乌龟。然后有的乌龟在说谎,问最少有多少只乌龟在说话,是哪几只。

思路:假设乌龟都是朝右看的。那么把乌龟离散到1~n的范围中,若一只乌龟前面有b只,后面有a只,那么这只乌龟就在[a + 1, n - b]的范围内。那么对每只乌龟就有一个所在区间[l, r]。那么对一对乌龟,如果区间完全重叠,那么说明这两只乌龟应该站在同一个位置,所以区间[l, r]的权就为乌龟的区间等于[l, r]的总数。那么就是求不重叠区间的最大权,用DP求即可。

弱证明:如果一只乌龟认为自己在区间[l, r]中,那么[l, r]里面一定需要有l - r + 1(即n - a - b)只乌龟,所以[l, r]里面的乌龟都说的话都应该相同,这也是区间不能相交的原因。其次,得出了不能相交的区间,那么我们一定能把说谎的那些乌龟拿出来摆到1~n中空的位置去,使得说真话的乌龟说真话。

填坑:并非两只乌龟在同一个位置就说话共真假,有可能有10只乌龟认为自己在区间[1, 1]中,但是[1, 1]实际上只能容纳一只乌龟,所以至少会有9只乌龟在说谎。其次,对于a+b≥n的煞笔乌龟毫无疑问在说谎。

代码(32MS,每次交都不一样无力吐槽):

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int MAXN = 1010;
 8 
 9 struct Node {
10     int l, r, pow, id;
11     bool operator < (const Node &rhs) const {
12         if(r != rhs.r) return r < rhs.r;
13         return l < rhs.l;
14     }
15     bool operator == (const Node &rhs) const {
16         return l == rhs.l && r == rhs.r;
17     }
18 };
19 
20 int n;
21 Node a[MAXN];
22 int dp[MAXN], pre[MAXN], last[MAXN];
23 bool use[MAXN], ans[MAXN];
24 
25 void solve() {
26     memset(dp, 0, sizeof(dp));
27     int cur = 0;
28     for(int i = 1; i <= n; ++i) {
29         pre[i] = i - 1;
30         dp[i] = dp[i - 1];
31         last[i] = -1;
32         while(cur < n && a[cur].r == i) {
33             if(dp[i] < dp[a[cur].l - 1] + a[cur].pow) {
34                 pre[i] = a[cur].l - 1;
35                 dp[i] = dp[a[cur].l - 1] + a[cur].pow;
36                 last[i] = cur;
37             }
38             ++cur;
39         }
40     }
41 }
42 
43 void output() {
44     int cur = n;
45     while(cur > 0) {
46         if(last[cur] != -1) use[last[cur]] = true;
47         cur = pre[cur];
48     }
49     for(int i = n - 1; i > 0; --i)
50         if(use[i] && a[i] == a[i - 1]) use[i - 1] = true;
51     printf("%d", n - dp[n]);
52     for(int i = 0; i < n; ++i) ans[a[i].id] = !use[i];
53     for(int i = 1; i <= n; ++i) if(ans[i]) printf(" %d", i);
54     puts("");
55 }
56 
57 int main() {
58     while(scanf("%d", &n) != EOF) {
59         for(int i = 0; i < n; ++i) {
60             int x, y;
61             scanf("%d%d", &x, &y);
62             a[i].l = x + 1;
63             a[i].r = n - y;
64             if(x + y >= n) a[i].r = n + 1;
65             a[i].pow = 1;
66             a[i].id = i + 1;
67         }
68         sort(a, a + n);
69         for(int i = 0; i < n - 1; ++i)
70             if(a[i] == a[i + 1]) a[i + 1].pow += a[i].pow;
71         for(int i = 0; i < n; ++i)
72             a[i].pow = min(a[i].pow, a[i].r - a[i].l + 1);
73         solve();
74         output();
75     }
76 }
View Code
原文地址:https://www.cnblogs.com/oyking/p/3294381.html