USACO FEB08 Silver Eating Together 麻烦的聚餐
由于结果要分两种情况(不下降序列和不上升序列),要进性两遍动态规划
状态设定
* 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;
}