USACO FEB08 Silver Eating Together 麻烦的聚餐

This post is written in Chinese. Please consider using Google Translate

由于结果要分两种情况(不下降序列和不上升序列),要进性两遍动态规划

状态设定

* F[i,j]表示前i个数中,第i个数改为j时,满足不下降序列所需的一共最少更改次数。
* G[i,j]表示前i个数中,第i个数改为j时,满足不上升序列所需的一共最少更改次数。 

状态转移方程

* F[i,j]=
      o Min{ F[i-1,k] (1<=k<=j) } + 1 (当第i个数不为j时,需要更改)
      o Min{ F[i-1,k] (1<=k<=j) } (当第i个数为j时,不需更改) 

* G[i,j]=
      o Min{ G[i-1,k] (j<=k<=3) } + 1 (当第i个数不为j时,需要更改)
      o Min{ G[i-1,k] (j<=k<=3) } (当第i个数为j时,不需更改) 

边界条件

* F[0,k]=G[0,k]=0 (1<=k<=3) 

目标结果

* Ans=Min{F[N,i],G[N,i]} (1<=i<=3) 
/*
ID: cmykrgb1
PROG: egroup
LANG: C++
*/

#include <iostream>
#define INF 0x7FFFFFFF
#define MAX 30001

using namespace std;

int F[MAX][4];
int S[MAX];
int N,Ans=INF;

void init()
{
    int i;
    freopen("egroup.in","r",stdin);
    freopen("egroup.out","w",stdout);
    cin >> N;
    for (i=1;i<=N;i++)
        cin >> S[i];
}

void dynamic()
{
    int i,j,k;
    for (j=1;j<=3;j++)
    {
        for (i=1;i<=N;i++)
        {
            F[i][j]=INF;
            for (k=1;k<=j;k++)
            {
                if (F[i-1][k]<F[i][j])
                    F[i][j]=F[i-1][k];
            }
            if (S[i]!=j)
                F[i][j]++;
        }
        if (F[N][j]<Ans)
            Ans=F[N][j];
    }
    for (j=3;j>=1;j--)
    {
        for (i=1;i<=N;i++)
        {
            F[i][j]=INF;
            for (k=j;k<=3;k++)
            {
                if (F[i-1][k]<F[i][j])
                    F[i][j]=F[i-1][k];
            }
            if (S[i]!=j)
                F[i][j]++;
        }
        if (F[N][j]<Ans)
            Ans=F[N][j];
    }
}

int main()
{
    init();
    dynamic();
    cout << Ans << endl;
    return 0;
}

Related posts