http://poj.org/problem?id=2127
这道题目就是求两个序列的最长公共上升子序列,序列的长度不超过500,那么我们使用O(N^3)复杂度的算法也能过。
我们假设数组A和B分别为这两个序列,我们定义状态dp[i][j]表示以A[i]和B[j]结尾的并且LCIS的最后一个元素小于A[i]的值,也就是说dp[i][j]并不一定是串A[1--i]和串B[1--j]的LCIS,因为多了一个限制就是该LCIS的最后一个元素必须小于A[i]。那么闲杂我们看看如何来进行状态转移呢?
如果A[i] == B[j],那么dp[i][j] = max(dp[i`][j-1]) +1;(1<i`<i)
否则dp[i][j] = dp[i][j-1]
路径的话我们只需要在转移的时候进行记录就行了,输出的时候注意判断结束的条件。
但是这道题很诡异的就是交上去,同一个代码,时而AC时而WA,很不理解。下面贴上代码,希望知道为什么会出现这种诡异现象的大牛能够给予指导,谢谢。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX = 505;
int dp[MAX][MAX];
int a[MAX],b[MAX];
typedef struct NODE
{
int x, y;
}Node;
Node path[MAX][MAX];
void print(int n, int m)
{
//printf("%d %d %d %d\n", n, m, a[n], a[m]);
if(n == -1 || m == -1)
return ;
int x = path[n][m].x;
int y = path[n][m].y;
if(dp[x][y] > 0)
print(x, y);
if(a[n] == b[m])
printf("%d ", a[n]);
}
int main()
{
int n,m;
while(scanf("%d", &n) != EOF)
{
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
scanf("%d", &m);
for(int i=1; i<=m; i++)
scanf("%d", &b[i]);
memset(dp, 0, sizeof(dp));
int ansans = 0;
int ansx, ansy;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
int ans = 0;
int x = -1, y = -1;
if(a[i] == b[j])
{
for(int k=i-1; k>=1; k--)
{
if(a[k]<a[i]&&dp[k][j-1]>ans)
{
ans = dp[k][j-1];
x = k;
y = j-1;
}
}
ans ++;
}
else
{
ans = dp[i][j-1];
x = i;
y = j-1;
}
dp[i][j] = ans;
path[i][j].x = x;
path[i][j].y = y;
if(ansans < ans)
{
ansans = ans;
ansx = i;
ansy = j;
}
}
}
printf("%d\n", ansans);
if(ansans == 0)
{
printf("\n");
continue;
}
print(ansx, ansy);
printf("\n");
}
return 0;
}