poj 3671 3670——简单DP

大意:给你一串只有1,2的数字,让你改变最少的次数,让这个序列变成非递减的。

先开始看这个题目,完全不会做,去网上百度了一下,居然说这个题是求最长非递减子序列的长度,但是用nlogn算法求非严格递增的子序列长度我不会,只能另想办法。在网上搜到了一个神码,我现在都不知道为什么:

#include<cstdio>

int i,n,a,f[3]={0};

int main()

{

scanf(
"%d",&n);

for(i=0;i<n;++i)

{

scanf(
"%d",&a),++f[a];

if(f[2]<f[1])f[2]=f[1];

}

printf(
"%d\n",n-f[2]);

}

后来我自己想了一个。

开一个dp[30010][3]的数组

其中dp[i][j]表示把第i个数改成j最少要花多少次

那么状态转移方程就列出来了:

令a=1        j!=a[i]

       0        j==a[i]

那么dp[i][1]=dp[i-1][1]+a;

      dp[i][2]=min(dp[i-1][1],dp[i-1][2])+a;

#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>
#define MAXN 30010

int dp[MAXN][3];

int min(int a,int b)
{
return a>b?b:a;
}

int main(void)
{

int n;

scanf(
"%d",&n);

for(int i=1;i<=n;i++)
{

int a;

scanf(
"%d",&a);

int b=(a==1?0:1);

dp[i][
1]=dp[i-1][1]+b;

b
=!b;

dp[i][
2]=min(dp[i-1][1],dp[i-1][2])+b;

}

printf(
"%d\n",min(dp[n][1],dp[n][2]));

}

poj 3670 也和这个类似,只是有1,2,3数,然后递减也可以:

#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>
#define MAXN 30010

int dp[MAXN][4];
int dp2[MAXN][4];

int min(int a,int b)
{
return a>b?b:a;
}

int main(void)
{
int t;
scanf(
"%d",&t);
for(int i=1;i<=t;i++)
{
int a;
scanf(
"%d",&a);
int b=(a==1?0:1);
int c=(a==3?0:1);
dp[i][
1]=dp[i-1][1]+b;
dp2[i][
3]=dp2[i-1][3]+c;
b
=(a==2?0:1);
int m=min(dp[i-1][1],dp[i-1][2]);
int n=min(dp2[i-1][3],dp2[i-1][2]);
dp[i][
2]=m+b;
dp2[i][
2]=n+b;
m
=min(m,dp[i-1][3]);
n
=min(n,dp2[i-1][1]);
b
=(a==3?0:1);
c
=(a==1?0:1);
dp[i][
3]=m+b;
dp2[i][
1]=c+n;
}
int m=min(dp[t][2],dp[t][1]);
m
=min(m,dp[t][3]);
int n=min(dp2[t][1],dp2[t][2]);
n
=min(n,dp2[t][3]);
printf(
"%d\n",min(m,n));
}

你可能感兴趣的:(poj)