poj1159(dp,最长公共子序列)

来源:互联网 发布:孰轻孰重言知知妈妈网 编辑:程序博客网 时间:2024/06/05 19:27

  题目的大概意思就是给你一个字符串,然后可以往字符串里面插入字符,要计算出至少插入多少个字符,可以让它形成一个回文串。

  做法就是生成一个新串,该新串是原串的逆序串,然后求两个串的最长公共子序列就好。

  动归方程:

  dp[i][j] = max( dp[i-1][j], dp[i][j-1], dp[i-1][j-1] + ( s1[i] == s2[j] ? 1 : 0 ) );

  动归求最长公共子序列还可以转化为求最长上升子序列,就是找到第一个串中的每个字符在第二串中出现的位置,然后逆序,求出最长上升子序列(绝对上升)。学习这种方法的链接

   另外题目直接开dp[5001][5001]会MLE,所以要使用滚动数组。

  

#include "stdio.h"#include "string.h"#include "math.h"#include <string>#include <queue>#include <stack>#include <vector>#include <map>#include <algorithm>#include <iostream>using namespace std;#define MAXM 1#define MAXN 1#define max(a,b) a > b ? a : b#define min(a,b) a < b ? a : b#define Mem(a,b) memset(a,b,sizeof(a))int Mod = 1000000007;double pi = acos(-1.0);double eps = 1e-6;typedef struct{int f,t,w,next;}Edge;Edge edge[MAXM];int head[MAXN];int kNum;void addEdge(int f, int t, int w){edge[kNum].f = f;edge[kNum].t = t;edge[kNum].w = w;edge[kNum].next = head[f];head[f] = kNum ++;}int dp[2][5005];char s1[5005], s2[5005];int N;void solve(){getchar();scanf("%s", s1);for(int i = 0; i < N; i ++){s2[i] = s1[N-1-i];}s2[N] = 0;for(int i = 0; i <= N; i ++){dp[0][i] = 0;}for(int i = 1; i <= N; i ++){dp[i&1][0] = 0;for(int j = 1; j <= N; j ++){dp[i&1][j] = 0;if( s1[i-1] == s2[j-1] ){dp[i&1][j] = dp[(i-1)&1][j-1] + 1; }else{dp[i&1][j] = dp[(i-1)&1][j-1]; }dp[i&1][j] = max(dp[i&1][j], dp[i&1][j-1]);dp[i&1][j] = max(dp[i&1][j], dp[(i-1)&1][j]);}}printf("%d\n",N - dp[N&1][N]);}int main(){//freopen("d:\\test.txt", "r", stdin);while(cin>>N){solve();}return 0;}

0 0
原创粉丝点击