链接:http://codeforces.com/contest/1114/problem/D
来源:Codeforces
题意就是,我们有一串数字,如果两个相邻数字不同我们可以更改任意一个数字使他们相同,最后改成所有数都相同的数字.我们要找的就是修改次数最小的方法,并且输出这个最小次数.
详细解释见代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#define pi 3.1415926
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
//typedef pair<int,int> Node;
typedef long long LL;
const LL Max_n=5005;
vector<LL>prime;
map<LL,LL>cnt;
int a[Max_n],dp[Max_n][Max_n][2];//k表示两种合并方式
//dp[i][j][0]合并成左边的颜色的最小次数
//dp[i][j][1]合并成右边的颜色的最小次数
//dp[l][r][0]=min(dp[l+1][r][0]+(a[l]!=a[l+1]),dp[l+1][r][1]+(a[l]!=a[r])) 变成l的颜色
//dp[l][r][1]=min(dp[l][r-1][0]+(a[l]!=a[r]),dp[l][r-1][1]+(a[r-1]!=a[r])) 变成r的颜色
int main(){
int n;
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) {
dp[i][j][0] = dp[i][j][1] = (i == j) ? 0 : inf;//i=j时不需要操作
}
}
for(int d=2;d<=n;++d){//合并成的区间长度
for(int l=0;l+d-1<n;++l){//左边界(注意右边界范围)
int r=l+d-1;//右边界
//dp[l][r][0]:只能变成a[l]的颜色,上一次合并的颜色有两种(选择了其中一种进行合并):a[l+1],a[r]
dp[l][r][0]=min(dp[l+1][r][0]+(a[l]!=a[l+1]),dp[l+1][r][1]+(a[l]!=a[r]));
//dp[l][r][1]:只能变成a[r]的颜色,上一次合并的颜色有两种(选择了其中一种进行合并):a[l],a[r-1]
dp[l][r][1]=min(dp[l][r-1][0]+(a[r]!=a[l]),dp[l][r-1][1]+(a[r]!=a[r-1]));
}
}
//我们每次都把两种合并情况算了出来
printf("%d\n",min(dp[0][n-1][0],dp[0][n-1][1]));
return 0;
}