題目鏈接
題目描述
"lalala,我是一個快樂的粉刷匠",小名一邊快活地唱着歌,一邊開心地刷着牆",興致突然被打斷,"小名,你今天如果刷不完這一棟樓的牆,那麼你就等着被炒魷魚吧",老闆聲嘶力竭的吼着。苦惱的小名因爲不想被炒魷魚,所以希望儘量快地刷完牆,由於他本人的數學基礎很差,他現在請你來幫助他計算最少完成每一堵牆需要刷多少次。每一面牆有n個段,對於每個段指定一個目標顏色ci。剛開始的時候所有的牆壁爲白色,我們現在有一個刷子,刷子長度爲k,刷子每次可以選擇一種顏色,然後選擇段數爲(1~k)連續的牆段刷成選擇的一種顏色。我們現在想要知道,爲了把牆變成目標顏色,最少刷多少次(保證指定的目標顏色一定不爲白色)。
輸入描述:
對於每一個案例,我們第一行包括兩個整數n,k(1<=n<=100,1<=k<=50,k<n),表示牆的長度爲n,刷子的長度爲k。第二行輸入n個整數(c1c2...cn),(1<=ci<=256),表示對於牆的每一段指定的顏色。
輸出描述:
輸出一個數,表示小名最少刷多少次。
樣例輸入:
樣例1
3 3
1 2 1
樣例2
5 4
5 4 3 3 4
樣例輸出:
樣例1
2
樣例2
3
code:
在找斷點k之前,有初始化的dp[i][j]=dp[i+1][j]+1,有長度限制kk,所以要分兩種情況
第一種:當我枚舉長度len<=kk時,在枚舉斷點k時,要先判斷c[i] == c[k],如果相等有轉移方程dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]),因爲此時第i個已經等於第k個,而我的刷子長度大於這個區間長度,所以第k個的顏色就肯定和第i個是一起塗好的纔是最小的操作次數。而枚舉k的時候,要枚舉到j。
第二種:當len>k時,直接枚舉斷點即可,也要枚舉到j
(以上思路參考休想騙我打代碼 的博客)
#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn];
int dp[maxn][maxn];
int n,kk;
int main()
{
scanf("%d%d",&n,&kk);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
dp[i][i]=1;
}
for(int len=2;len<=n;len++){
for(int i=1;i<=n;i++){
int j=len+i-1;
if(j>n)break;
dp[i][j]=dp[i+1][j]+1;
if(len<=kk){
for(int k=i+1;k<=j;k++){
if(a[k]==a[i])dp[i][j]=min(dp[i][j],dp[i+1][k]+dp[k+1][j]);
}
}
else{
for(int k=i;k<=j;k++){
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
}
}
printf("%d\n",dp[1][n]);
return 0;
}