DP - hdu5009 Paint Pearls

来源:互联网 发布:1.5厚js防水涂料用量 编辑:程序博客网 时间:2024/06/04 18:26

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5009


题意:

有一串珠子需要染色,允许每次染一段区间,代价为这段区间的颜色总数color^2,求最小代价


思路:

感觉就是DP,然而就是搞不出怎么DP给跪了

先提出一个基础的DP思路 dp[i] = min{dp[j]+num[j+1,i]^2},dp[i]代表[1,i]这段区间的代价,0<=j<i,num为对应区间的颜色总数,显然,这么构建状态转移方程的情况下时间复杂是O(n^2),需要优化

以第二组测试数据为例,dp[9] = min{dp[8] + 1, dp[7] + 4, dp[6]+ 9, dp[0] + 9},嗯...嗯?!中间的dp[54321]哪去了!!事实上,中间的d[6],dp[5],dp[4]..是不需要考虑的,回头看状态转移方程,事实上这么转移是将[j+1,i]视为一段区间进行全体染色,则dp[6]+9,代表dp[6] + 对颜色{2,3,4}进行区间染色,则无论是[1,9][2,9][3,9]..[6,9]这些区间都是对颜色{2,3,4}进行区间染色,代价相同没有考虑的必要,直接跳到dp[0]的状态进行判断

因此,可以发现,每种颜色只要保留最后出现的位置即可,实现方式为数组模拟双向链表,具体看代码,反正也不长……


代码:

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>#include <map>using namespace std;const int MAXINT = 0x7FFFFFFF;const int MAXSIZE = 5*1e4 + 100;int dp[MAXSIZE];int pre[MAXSIZE];int nxt[MAXSIZE];int arr[MAXSIZE];map<int, int> M;int main(){    int n;    while (scanf("%d",&n)!=EOF){        for (int i=1;i<=n;++i){            scanf("%d",arr+i);            pre[i] = i-1;            nxt[i] = i+1;        }        pre[0] = -1;        for (int i=1;i<=n;++i) dp[i] = MAXINT;        dp[0] = 0;        M.clear();        for (int i=1;i<=n;++i){            if (!M.count(arr[i])) M[arr[i]] = i;            else {                int t = M[arr[i]];                nxt[pre[t]] = nxt[t];                pre[nxt[t]] = pre[t];                M[arr[i]] = i;            }            int cnt = 1;            for (int j=pre[i];j!=-1;j=pre[j]){                dp[i] = min(dp[j]+cnt*cnt, dp[i]);                cnt++;                if (cnt*cnt>n) break;            }        }        printf("%d\n",dp[n]);    }    return 0;}



0 0
原创粉丝点击