Time Limit: 10000MS | Memory Limit: 65536K | |
Total Submissions: 10340 | Accepted: 2727 | |
Case Time Limit: 2000MS | Special Judge |
Description
Sequence S 1 , S 2 , . . . , S N of length N is called an increasing subsequence of a sequence A 1 , A 2 , . . . , A M of length M if there exist 1 <= i 1 < i 2 < . . . < i N <= M such that S j = A ij for all 1 <= j <= N , and S j < S j+1 for all 1 <= j < N .
Input
Output
Sample Input
5 1 4 2 5 -12 4 -12 1 2 4
Sample Output
2 1 4
Source
链接:http://poj.org/problem?id=2127
思路:也是一道模板题,求最长递增公共子序列,并记录路径返回输出;
状态:dp[i][j]表示以s1串的前i个字符s2串的前j个字符且以s2[j]为结尾构成的LCIS的长度。
状态转移:当 s1[i-1]!=s2[j-1]时,按照lcs可知由2个状态转移过来,dp[i-1][j],dp[i][j-1],因为dp[i][j]是以s2[j]为结尾构成的LCIS的长度。所以s2[j-1]一定会包含在里面,所以舍去dp[i][j-1],只由dp[i-1][j] 转移过来。
当s1[i-1]==s2[j-1],这时肯定要找前面s1[ii-1]==s2[jj-1]的最长且比s2[j-1]小的状态转移过来.
若s1[i-1]!=s2[j-1] 那么dp[i][j]=dp[i][j-1]
若s1[i-1]==s2[j-1] 那么dp[i][j]=MAX{dp[i-1][k]+1(0<k<j),s2[k-1]<s2[j-1]};
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n,m,a[505],b[505];
int dp[505][505];
int rd[505][505];
void LICS()
{
int ans=0;
// int dp[505]={0};
int mac=0;//用来记录路径的中间变量
int I,J;//最后的坐标
int lu[505];//用来最后输出路径
for(int i=1;i<=n;i++)
{
int len=0; //长度
for(int j=1;j<=m;j++)
{
int k=dp[i][j]=dp[i-1][j];
if(len<k && a[i]>b[j])
{
len=k;//记录相等前小于a[i]的最大长度
mac=j;
}
if(a[i]==b[j])
{
dp[i][j]=len+1;
rd[i][j]=mac;//记录最大长度下,上一个j的坐标
}
if(ans<dp[i][j])//更新最大长度,并记录结尾的坐标
{
ans=dp[i][j];
I=i;
J=j;
}
}
}
/* printf("(%d,%d)\n",I,J);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
printf("%d ",rd[i][j]);
}
printf("\n");
}*/
printf("%d\n",ans);
int Len=ans;
if(Len>0)
{
lu[Len--]=J;
}
while(Len && I && J)
{
// printf("(%d,%d),rd=%d\n",I,J,rd[I][J]);
if(rd[I][J]>0)
{
lu[Len--]=rd[I][J];
J=rd[I][J];
}
I--;
}
for(int i=1;i<=ans;i++)
{
printf("%d ",b[lu[i]]);
}
printf("\n");
}
int main()
{
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]);
}
LICS();
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n,m,a[505],b[505];
//int dp[505][505];
int rd[505][505];
/*****
题意:求最长上升公共子序列(LCIS),并记录路径.
状态:dp[i][j]表示以s1串的前i个字符s2串的
前j个字符且以s2[j]为结尾构成的LCIS的长度。
状态转移:当 s1[i-1]!=s2[j-1]时,按照lcs可知由2个状态转移过来,
dp[i-1][j],dp[i][j-1],因为dp[i][j]是以s2[j]为结尾构
成的LCIS的长度。所以s2[j-1]一定会包含在里面,所以
舍去dp[i][j-1],只由dp[i-1][j] 转移过来。
当s1[i-1]==s2[j-1],这时肯定要找前面s1[ii-1]==s2[jj-1]的最长且比s2[j-1]小的状态转移过来.
若s1[i-1]!=s2[j-1] 那么dp[i][j]=dp[i][j-1]
若s1[i-1]==s2[j-1] 那么dp[i][j]=MAX{dp[i-1][k]+1(0<k<j),s2[k-1]<s2[j-1]};
*/
void LICS()
{
int ans=0;
int dp[505]={0};
int mac=0;//用来记录路径的中间变量
int I,J;//最后的坐标
int lu[505];//用来最后输出路径
// memset(dp,0,sizeof(dp));//全局变量默认初始化,可以不写这句
for(int i=1;i<=n;i++)
{
int len=0; //长度
for(int j=1;j<=m;j++)
{
/**按照lcs可知由2个状态转移过来,dp[i-1][j],dp[i][j-1],
因为dp[i][j]是以s2[j]为结尾构成的LCIS的长度。
所以s2[j-1]一定会包含在里面,所以舍去dp[i][j-1],
只由dp[i-1][j] 转移过来。*/
/***由于只和dp[i-1][j]有关,所以优化空间降维***/
// int k=dp[i][j]=dp[i-1][j];
int k=dp[j];
if(len<k && a[i]>b[j])
{
len=k;//记录相等前小于a[i]的最大长度
mac=j;
}
if(a[i]==b[j])
{
dp[j]=len+1;
rd[i][j]=mac;//记录最大长度下,上一个j的坐标
}
if(ans<dp[j])//更新最大长度,并记录结尾的坐标
{
ans=dp[j];
I=i;
J=j;
}
}
}
/* printf("(%d,%d)\n",I,J);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
printf("%d ",rd[i][j]);
}
printf("\n");
}*/
printf("%d\n",ans);
int Len=ans;
if(Len>0)
{
lu[Len--]=J;
}
while(Len && I && J)
{
// printf("(%d,%d),rd=%d\n",I,J,rd[I][J]);
if(rd[I][J]>0)
{
lu[Len--]=rd[I][J];
J=rd[I][J];
}
I--;
}
for(int i=1;i<=ans;i++)
{
printf("%d ",b[lu[i]]);
}
printf("\n");
}
int main()
{
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]);
}
LICS();
}
return 0;
}