题意:
给出很多个石头,围成一圈。现在要求将石头染成给定的颜色,但是限制了每次最多只能染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
*/