您的位置:首页 > 其它

POJ 3670(最长递增子序列 LIS)

2016-08-14 00:29 411 查看
点击打开链接

题意:给定一串数字,求改变最小的数字使其变成升序或降序排列。暴力是不可能的,写着写着就把自己写晕了。看了他人的思路,使用DP写的,自己也推了一会,虽然是看过别人的思路才会的自己也推出来了,但是还是希望下次靠自己就能推出DP公式吧。其实这是一个LIS(最长上升子序列),只要求出最长LIS的长度,用总数减去就是答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
const int maxn = 30000 + 5;
const int inf = 0x3f3f3f3f;
const double eps = 0.00000000000001;
int a[maxn];
int dp[maxn][4];
int n;
int solve(int *a)//dp[i][j]表示从第一位直至将第i位修改为j时为止总共进行了多少次修改
{
memset(dp, 0, sizeof(0));
dp[1][1] = dp[1][2] = dp[1][3] = 1;//第一位修改为1,2,3时均需修改一次就行
dp[1][a[1]] = 0;
for(int i = 1; i <= n; i++)
{
if(a[i] == 1)
dp[i][1] = dp[i - 1][1];//a[i]本身就是1,不需要进行修改,故等于将第i-1位修改为1时总共进行的修改次数
else
dp[i][1] = dp[i - 1][1] + 1;//a[i]不是1时,第i位需要进行一次修改
if(a[i] == 2)
dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]);//a[i]本身就是2时不需要修改第i位,故dp[i][2]的值为前一位为1或者为2时总共进行的修改次数(二者取最小)
else
dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]) + 1;
if(a[i] == 3)
{
dp[i][3] = min(dp[i - 1][1], dp[i - 1][2]);//a[i]本身就是3时不需要修改第i位,故dp[i][3]的值为前一位为1或者为2或者为3时总共进行的修改次数(三者取最小)
dp[i][3] = min(dp[i][3],  dp[i - 1][3]);
}
else
{
dp[i][3] = min(dp[i - 1][1], dp[i - 1][2]) + 1;
dp[i][3] = min(dp[i][3], dp[i - 1][3] + 1);
}

}
return min(dp
[1], min(dp
[2], dp
[3]));//返回最小值
}
int main()
{
while(~scanf("%d",&n))
{
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
// memset(dp, 0, sizeof(dp));
int sum = solve(a);//求升序
reverse(a + 1, a + 1 + n);//将a翻转后求逆序
sum = min(sum, solve(a));
printf("%d\n",sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: