题目传送门:http://poj.org/problem?id=3670
题意:一个字符串只由1或2或3组成,要求使得字符串变为(1*)(2*)(3*)(星号代表字符数出现次数为任意次),或(3*)(2*)(1*)这样的字符串(如1112223333 或 332111),问最少需要改变多少个字符?
解题思路:考虑dp,设dp[i][j]为截至到字符串第i位,第i位的字符为j时,所需改变的最少字符数。
初始化第一位的情况,然后从第二位开始向后递推。
dp1数组代表的是递增的情况,dp2数组代表的是递减的情况。
最终答案为min(dp1[n][1],dp1[n][2],dp1[n][3],dp2[n][1],dp2[n][2],dp2[n][3])。
#include<cstdio>
#include<algorithm>
using namespace std;
int a[30005];
int dp1[30005][4];
int dp2[30005][4];
const int INF = 0x3f3f3f3f;
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
memset(dp1,INF,sizeof(dp1));
memset(dp2,INF,sizeof(dp2));
if (a[1] == 1)
{
dp1[1][1] = dp2[1][1] = 0;
dp1[1][2] = dp2[1][2] = 1;
dp1[1][3] = dp2[1][3] = 1;
}
else if (a[1] == 2)
{
dp1[1][1] = dp2[1][1] = 1;
dp1[1][2] = dp2[1][2] = 0;
dp1[1][3] = dp2[1][3] = 1;
}
else
{
dp1[1][1] = dp2[1][1] = 1;
dp1[1][2] = dp2[1][2] = 1;
dp1[1][3] = dp2[1][3] = 0;
}
for (int i = 2; i <= n; i++)
{
if (a[i] == 1)//原字符串当前位为1
{
//这一位是1的话,前一位合法的情况只能为1(递增),并且由于当前a[i]为1,所以不需改变字符
dp1[i][1] = dp1[i-1][1];
//前一位合法的情况为1和2,因为原字符串当前位为1,现在的情况是当前位为2,所以需要改变字符,改变数+1
dp1[i][2] = min(dp1[i-1][1],dp1[i-1][2]) + 1;
//前一位合法的情况为1或2或3,因为原字符串当前位位1,现在的i是当前位位2,所以需要改变字符,改变数+1
dp1[i][3] = min(dp1[i-1][1],min(dp1[i-1][2],dp1[i-1][3])) + 1;
}
else if (a[i] == 2)
{
dp1[i][1] = dp1[i-1][1] + 1;
dp1[i][2] = min(dp1[i-1][1],dp1[i-1][2]);
dp1[i][3] = min(dp1[i-1][1],min(dp1[i-1][2],dp1[i-1][3])) + 1;
}
else
{
dp1[i][1] = dp1[i-1][1] + 1;
dp1[i][2] = min(dp1[i-1][1],dp1[i-1][2]) + 1;
dp1[i][3] = min(dp1[i-1][1],min(dp1[i-1][2],dp1[i-1][3]));
}
}
for (int i = 2; i <= n; i++)
{
if (a[i] == 1)
{
dp2[i][1] = min(dp2[i-1][1],min(dp2[i-1][2],dp2[i-1][3]));
dp2[i][2] = min(dp2[i-1][2],dp2[i-1][3]) + 1;
dp2[i][3] = dp2[i-1][3] + 1;
}
else if (a[i] == 2)
{
dp2[i][1] = min(dp2[i-1][1],min(dp2[i-1][2],dp2[i-1][3])) + 1;
dp2[i][2] = min(dp2[i-1][2],dp2[i-1][3]);
dp2[i][3] = dp2[i-1][3] + 1;
}
else
{
dp2[i][1] = min(dp2[i-1][1],min(dp2[i-1][2],dp2[i-1][3])) + 1;
dp2[i][2] = min(dp2[i-1][2],dp2[i-1][3]) + 1;
dp2[i][3] = dp2[i-1][3];
}
}
int ans1 = min(dp1[n][1],min(dp1[n][2],dp1[n][3]));
int ans2 = min(dp2[n][1],min(dp2[n][2],dp2[n][3]));
printf("%d\n",min(ans1,ans2));
return 0;
}