LighOJ 1422

区间dp,dp[i][j]表示[i,j]的需要换的最小的衣服的件数,则若a[i] = a[j] ,
则dp[i][j] = min(dp[i+1][j],dp[i][j-1]), 否则要加上1,
然后枚举中间的点,看能否构成更优的解。
记忆化大法好 !


#include <cstdio>
#include <cstring>
#include <algorithm>
int t,n,a[110],d[110][110],cas;

using namespace std;
int dp(int i,int j){
	int & ans = d[i][j];
	if(ans != 1e9) return ans;
	if(i == j) return ans = 1;
	if(a[i] == a[j]) ans = min(dp(i,j-1),dp(i+1,j));
	else ans = min(dp(i+1,j),dp(i,j-1)) + 1;
	for(int k = i+1;k<j;k++)
		if(a[k] == a[i]) ans = min(ans,dp(i,k)+dp(k+1,j));
	return ans;
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i =0 ;i<n;i++) scanf("%d",a+i);
		for(int i = 0;i<n;i++) for(int j = 0;j<n;j++) d[i][j] = 1e9;
		printf("Case %d: %d\n",++cas,dp(0,n-1));
	}
	return 0;
} 

给上非递推版本,要注意i要从n-1推到0

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int t,n,a[110],dp[110][110],cas;
int main() {
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i =0 ;i<n;i++) scanf("%d",a+i);
		memset(dp,0,sizeof(dp));
		for(int i =0 ;i<n;i++) dp[i][i] =  1;
		for(int i =n-1 ;i>=0;i--){
			for(int j = i+1;j<n;j++){
				dp[i][j] = dp[i+1][j] + 1;
				if(a[i] == a[j]) dp[i][j] = dp[i][j-1];
				for(int k = i+1;k<j;k++)
					if(a[i] == a[k]) dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]);、
			}
		}
		printf("Case %d: %d\n",++cas,dp[0][n-1]);
	}
	return 0;

猜你喜欢

转载自blog.csdn.net/winhcc/article/details/88804552