【NOI2006】 千年虫

题目描述
千年虫是远古时代的生物,时隔几千万年,千年虫早已从地球上销声匿迹,
人们对其知之甚少。考古生物学家最近开始对其有了兴趣,
因为一批珍贵的千年虫化石被发现,这些化石保留了千年虫近乎完整的形态。
理论科学家们根据这些化石归纳出了千年虫的一般形态特征模型,
并且据此判定出千年虫就是蜈蚣的祖先!但科学家J发现了实际与理论
的一些出入,他仔细的研究了上百个千年虫化石,发现其中大部分千年虫的
形态都不完全符合理论模型,这到底是什么因素造成的呢?理论科学家K敏
锐的指出,千年虫的形态保存在化石中很有可能发生各种变化,即便最细
微的变化也能导致它不符合模型。于是,摆在科学家面前的新问题诞生了:
判断一个化石中的千年虫与理论模型的差距有多大?
具体来说,就是根据一个千年虫化石的形态A,找到一个符合理论模型的形态B,使 得B是最有可能在形成化石时变成形态A。 理论学家提出的“千年虫形态特征模型”如下(如上图所示):躯体由头、尾、躯干、足四大部分构成。 
1.头,尾用一对平行线段表示。称平行于头、尾的方向为x方向;垂直于x的方向为y方向;
 2.在头尾之间有两条互不相交的折线段相连,他们与头、尾两条线段一起围成的区域称为躯干,两条折线段都满足以下条件:拐角均为钝角或者平角,且包含奇数条线段,从上往下数的奇数条垂直于x方向。 
3.每条折线段从上往下数的第偶数条线段的躯干的另一侧长出一条足,即一个上、下底平行于x方向的梯形或矩形,且其中远离躯干一侧的边垂直于x方向。
注意:足不能退化成三角形(即底边的长度均大于零),躯干两侧足的数目可以不一样。
(如下图,左边有4条足,右边有5条足) 可见,x-y直角坐标系内,躯干和所有足组成的实心区域的边界均平行或垂直于坐标轴。
为了方便,我们假设所有这些边界的长度均为正整数。因此可以认为每个千年虫的躯体都由一些单位方格拼成。每个单位方格都由坐标(x,y)唯一确定。
设头尾之间的距离为n,则我们可以用2×n个整数来描述一条千年虫B(如右图):将B沿平行x轴方向剖分成n条宽度为1的横条,每个横条最左边一格的x坐标设为Li,最右一格的的x坐标设为Ri。则(n,L1,L2,..,Ln,R1,R2,..Rn)就确定了一条千年虫。
由于岁月的侵蚀,在实际发现的化石中,千年虫的形状并不满足上面理论模型的规则,一些格子中的躯体已经被某些矿物质溶解腐蚀了。地质、物理、生物学家共同研究得出:
 1、腐蚀是以格子为单位的,只能一整格被腐蚀;
 2、腐蚀是分步进行的,每一步只有一格被腐蚀; 
3、如果去掉一个格子后躯体不连通了,那么这个格子当前不会被腐蚀; 
4、如果一个格子的左边邻格和右边邻格都还没被腐蚀,那么这个格子当前不会被腐蚀; 
5、与头相邻的格子不能全部被腐蚀,与尾相邻的格子不能全部被腐蚀;倘若满足上面五条,我们仍然可以用(n,L’1,L’2,..,L’n,R’1,R’2,..R’n)来描述一个化石里头的千年虫的形态。其中L’i≤R’i。
例如下图: 现在你的任务是,输入一个化石里的千年虫的描述A,找一个满足理论模型的千年虫的描述B,使得B可以通过腐蚀过程得以变为A,且由B转化为A的代价(须被腐蚀的格子数)最少。输出此最小代价。

   

 

题解

 

DP——O(n^2)
 1 /*
 2     *Problem:    NOI2006 千年虫
 3     *Author :    Chen Yang
 4     *Time   :    2012.5.31 8:00 pm
 5     *State  :    40分
 6     *Memo   :    dp、维数优化
 7 */
 8 #include <cstdio>
 9 #include <cstdlib>
10 #include <cstring>
11 #include <string>
12 #include <algorithm>
13 using namespace std;
14 const int maxn = 100010, inf = 1000000000;
15 int n, ans, l[maxn], now[maxn], f[2][maxn][2], best0[maxn];
16 
17 void work()
18 {
19     memset(f, 0x7f, sizeof f);
20     memset(best0, 0x7f, sizeof best0);
21     int Max = 0;
22     for (int i=1; i<n+1; ++i) Max = max(Max, now[i]); Max++;
23     for (int i=0; i<=Max-now[1]; ++i) f[1][now[1]+i][0] = i;
24     int ths = 1, pst = 0;
25     for (int i=2; i<n+1; ++i)
26     {
27         ths ^= 1; pst ^= 1;
28         if (i>2) for (int j=now[i-2]; j<Max+1; ++j) f[ths][j][0] = f[ths][j][1] = inf;
29         int best1 = inf;
30         for (int j=now[i-1]; j<now[i]; ++j) best1 = min(best1, f[pst][j][0]);
31         for (int j=Max; j>now[i]; --j) best0[j] = min(f[pst][j][1],best0[j+1]);
32         for (int j=now[i]; j<Max+1; ++j)
33         {
34             if (j-1>=now[i-1]) best1 = min(best1, f[pst][j-1][0]);
35             f[ths][j][1] = min(f[pst][j][1], best1);
36             f[ths][j][0] = min(f[pst][j][0], best0[j+1]);
37             f[ths][j][1] += j-now[i]; f[ths][j][0] += j-now[i];
38         }
39     }
40     int Min = inf;
41     for (int i=now[n]; i<Max+1; ++i) Min = min(Min, f[ths][i][0]);
42     ans += Min;
43 }
44 
45 int main()
46 {
47     freopen("worm.in", "r", stdin);
48     freopen("worm.out", "w", stdout);
49     scanf("%d", &n);
50     for (int i=1; i<n+1; ++i) scanf("%d%d", l+i, now+i);
51     work();
52     for (int i=1; i<n+1; ++i) now[i] = maxn-l[i];
53     work();
54     printf("%d", ans);
55     return 0;
56 }

 

DP——O(n)
 1 /*
 2     *Problem:    NOI2006 千年虫
 3     *Author :    Chen Yang
 4     *Time   :    2012.5.31 10:00 pm
 5     *State  :    Solved
 6     *Memo   :    DP、维数优化、范围优化
 7 */
 8 #include <cstdio>
 9 #include <cstdlib>
10 #include <cstring>
11 #include <string>
12 #include <algorithm>
13 using namespace std;
14 const int maxn = 400010, inf = 100000000;
15 int n, ans, l[maxn], now[maxn], p[2], f[2][20][2], q[2][maxn];
16 
17 inline int getint()
18 {
19     int res = 0; char tmp;
20     while (!isdigit(tmp = getchar()));
21     do res = (res << 3) + (res << 1) + tmp - '0';
22     while (isdigit(tmp = getchar()));
23     return res;
24 }
25 
26 void work()
27 {
28     memset(f, 0x7, sizeof f); p[1] = 0;
29     for (int j=1; j<4; ++j) 
30     for (int k=now[j]; k<now[j]+3; ++k) if (k>=now[1]) q[1][++p[1]] = k;
31     for (int i=1; i<=p[1]; ++i) f[1][i][0] = q[1][i] - now[1];
32     int ths = 1, pst = 0;
33     for (int i=2; i<n+1; ++i)
34     {
35         ths ^= 1; pst ^= 1, p[ths] = 0; 
36         int a = i-2<1? 1:i-2, b = n<i+2? n:i+2;
37         for (int j=a; j<b+1; ++j) 
38         for (int k=now[j]; k<now[j]+3; ++k) if (k>=now[i]) q[ths][++p[ths]] = k;
39         for (int j=1; j<p[ths]+1; ++j)
40         {
41             f[ths][j][1] = inf, f[ths][j][0] = inf;
42             for (int k=1; k<p[pst]+1; ++k)
43             {
44                 //printf("%d %d\n", f[pst][k][0],f[pst][k][1]);
45                 if (q[pst][k]>q[ths][j]) f[ths][j][0] = min(f[ths][j][0], f[pst][k][1]); else
46                 if (q[pst][k]<q[ths][j]) f[ths][j][1] = min(f[ths][j][1], f[pst][k][0]); else
47                 f[ths][j][0] = min(f[ths][j][0], f[pst][k][0]),
48                 f[ths][j][1] = min(f[ths][j][1], f[pst][k][1]);
49             }
50             f[ths][j][0] += q[ths][j]-now[i], f[ths][j][1] += q[ths][j]-now[i];
51             //printf("%d %d\n", f[ths][j][0],f[ths][j][1]);
52         }
53     }
54     int Min = inf;
55     for (int i=1; i<p[ths]+1; ++i) Min = min(Min, f[ths][i][0]);
56     ans += Min;
57 }
58 
59 int main()
60 {
61     freopen("worm.in", "r", stdin);
62     freopen("worm.out", "w", stdout);
63     n = getint();
64     for (int i=1; i<n+1; ++i) l[i] = getint(), now[i] = getint();
65     work();
66     for (int i=1; i<n+1; ++i) now[i] = maxn-l[i];
67     work();
68     printf("%d", ans);
69     return 0;
70 }
posted @ 2012-06-02 21:50  datam  阅读(812)  评论(0编辑  收藏  举报