您的位置:首页 > 其它

Sdut1309不老传说(区间dp)

2014-12-11 22:13 357 查看
题意:

给出很多个石头,围成一圈。现在要求将石头染成给定的颜色,但是限制了每次最多只能染k个石头并且最大用c种颜色。

题解:

这题和hdu2476是换汤不换药的。怎么说呢?

首先我们考虑下杭电的那题(只要考虑如何从空串变为目标串),没限制颜色,好说。那么状态dp[i][j] 表示i到j刷成目标串的最小步数,那么有这样的决策对于i到j区间假设i+1到j已经刷完了,那么久单独刷i这个点,于是dp[i][j]=dp[i+1][j]+1;接下来就是要枚举断点更新,如果区间内某个点和断点i相等,说明可以分成两个段进行更行,即 dp[i+1][k]+dp[k+1][j]

为什么是i+1呢?想想如果i位置的串等于k位置的串那么i点刷k点肯定也是刷了,那么少了一个i点只有dp[i+1][k]是不是也是一样的呢?yes!因为如果没i点k点肯定要刷,那么决策的答案记为a,那现在i点加进去必然是要刷的,那i点和k点是同时刷的,那么决策的答案应该不变才对,于是dp[i][j] = max ( dp[i+1][k]+dp[k+1][j]) 这个方程就出来了。

好!现在言归正传,不老传说怎么做,这题限制了颜色的多少,那么我可以很郑重的说这个颜色的限制就是个幌子!为什么呢?

这样想,如果目标石头有5中颜色,那么我现在限定你用3中颜色,想想怎么刷都不可能刷成功,因为3中颜色根本变不了5中颜色!对其实这题限制的颜色是没用的,因为要达到目标,颜色肯定要是等于目标拥有的颜色!好了现在颜色的问题解决了!

那么现在问题来了!k个石头的限制怎么办!呵呵,这个简单多了,只要每次状态转移时判断是否子区间是否满足个数小于等于k就好了!

那么问题解决!

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
typedef long long lld;
#define oo 0x3f3f3f3f
#define mod 1000000007
#define maxn 400+5
int dp[maxn][maxn];
int a[maxn];

int main()
{
    int n,C,K,ans,t;
    while(scanf("%d %d %d",&n,&C,&K)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i+n]=a[i];
        }
        for(int i=1;i<=2*n;i++)
            for(int j=i+1;j<=2*n;j++)
                dp[i][j]=oo;
        for(int i=1;i<=2*n;i++)
            dp[i][i]=1;
        for(int L=2;L<=n;L++)
        {
            for(int i=1;i+L-1<2*n;i++)
            {
                int j=i+L-1;
                if(j-i+1<=K)
                    dp[i][j]=dp[i+1][j]+1;
                t=min(i+K-1,j);
                for(int k=i+1;k<=t;k++)
                    if(a[i]==a[k])
                        dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]);
            }
        }
        ans=oo;
        for(int i=1;i<=n;i++)
            ans=min(ans,dp[i][i+n-1]);
        printf("%d\n",ans);
    }
	return 0;
}
/*
4 3
0 0
0 4
4 0
1 1

4 10
0 0
0 4
4 4
4 0
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: