小小粉刷匠

題目鏈接

 

題目描述

"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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章