POJ 3670 Eating Together (DP)

题目传送门: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;
}
点赞