码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 5009 Paint Pearls

时间:2014-09-27 01:52:09      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   io   os   使用   ar   for   数据   

首先把具有相同颜色的点缩成一个点,即数据离散化。

然后使用dp[i]表示涂满前i个点的最小代价。对于第i+1个点,有两种情况:

1)自己单独涂,即dp[i+1] = dp[i] + 1

2)从第k个节点之后(不包括k)到第i+1个节点一次涂完,且一起涂的节点共有num种颜色,即dp[i+1] = dp[k] + num * num

从而可以得到状态转移方程dp[i+1] = min(dp[i], dp[k] + num * num)

但是如果从后往前遍历每一个k,会超时。

因此我们可以使用双向链表来把每种颜色最后出现的位置穿起来。对于每一个新加入的点,如果该点颜色没出现过,那么把它加入到双向链表的结尾。如果该点出现过,把它最后出现的位置从双向链表中删除,并把最新的位置加入到双向链表结尾。

需要注意的是要建立一个头节点,使得第一个节点不会因为后面出现了同样的颜色而被删除,从而无法计算从头到尾一次性涂完的情况。

第二个要注意的是如果num * num 已经大于了每个节点单独涂的代价 i,那么就没有必要再往前查找了。

代码如下:

 1 #define MAXN 50005
 2 #include <stdlib.h>
 3 #include <iostream>
 4 #include <stdio.h>
 5 #include <map>
 6 #include <limits.h>
 7 
 8 using namespace std;
 9 int arr[MAXN];//输入
10 int l[MAXN];//记录前一个最后出现的颜色的位置
11 int r[MAXN];//记录后一个最后出现颜色的位置
12 int dp[MAXN];//dp[i]表示涂到第i个节点最小的代价
13 int m;//离散化后数组的长度
14 
15 void solve()
16 {
17     map<int, int> exist;//map 存储出当前现过得颜色中,最后出现的位置
18     int last = 1;//双向链表尾
19     l[0] = -1;//头节点
20     r[0] = 1;//头节点
21     l[1] = 0;
22     exist[arr[1]] = 1;
23     dp[0] = 0;
24     dp[1] = 1;
25 
26     for( int i = 2 ; i < m ; i++ )
27     {
28        if( exist.count(arr[i]) == 0 )
29        {
30            r[last] = i;//添加到尾部
31            l[i] = last;
32            last = i;
33            exist[arr[i]] = i;
34        }
35        else
36        {
37             int tmp = exist[arr[i]];
38             r[l[tmp]] = r[tmp];//删除tmp
39             l[r[tmp]] = l[tmp];//删除tmp
40             r[last] = i;
41             l[i] = last;
42             last = i;
43             exist[arr[i]] = i;
44        }
45 
46        int k = last;
47        dp[i] = dp[i-1]+1;
48        int num = 1;
49        while( l[k] >= 0 )
50        {
51            dp[i] = min(dp[i], dp[l[k]] + num*num);
52            num++;
53            k = l[k];
54            if( num * num > i )//剪枝
55            {
56                break;
57            }
58        }
59     }
60     printf("%d\n", dp[m-1]);
61 }
62 
63 int main(int argc, char *argv[])
64 {
65     int n;
66     while(scanf("%d", &n) != EOF)
67     {
68         int a;
69         m = 1;
70         for( int i = 1 ; i <= n ; i++ )//从1开始,位置0是头节点
71         {
72             scanf("%d", &a);
73             if( i == 1 )
74             {
75                 arr[m++] = a;
76             }
77             else if( arr[m-1] !=  a )//合并相同颜色的节点,离散化
78             {
79                 arr[m++] = a;
80             }
81         }
82         solve();
83     }
84     return 0;
85 }

 

hdu 5009 Paint Pearls

标签:style   blog   color   io   os   使用   ar   for   数据   

原文地址:http://www.cnblogs.com/jostree/p/3995813.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!