zoukankan      html  css  js  c++  java
  • hdu 5009 Paint Pearls

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

    然后使用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
    ", 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 }
  • 相关阅读:
    convert image to base64 and post to RESTful wcf
    在android webview实现截屏的手动tounchmove裁剪图片
    How to use jquery ajax and android request security RESTful WCF
    using swfUpload in asp.net mvc
    using HttpClient and sending json data to RESTful server in adroind
    ODP.NET数据访问
    android image watermark
    解决国内不能访问github的问题
    idapro权威指南第二版阅读笔记第九章 交叉引用和绘图功能
    idapro权威指南第二版阅读笔记第二章 逆向和反汇编工具
  • 原文地址:https://www.cnblogs.com/jostree/p/3995813.html
Copyright © 2011-2022 走看看