问题描述:给n个数,找出最长子序列并输出
问题分析:本题是DAG(有向无环图)最长路问题,设d[i]为以i结尾的最长链的长度,则状态转移方程为:d[i]=max{0,d[j]|j<i && A[j]<A[i]}+1 ;
solve one: 这里用map[i][j]存储第i个和第j个的关系0-1邻接矩阵;套用标准解DAG的模板,利用dfs求解
#include<iostream> #include<algorithm> using namespace std; #define maxn 1000+5 int d[maxn],n,map[maxn][maxn]; //d[]用来存储以i结尾的最大长度,map[i][j]满足要求OK()关系的邻接矩阵 int A[maxn]; bool ok(int i,int j){ return j<i && A[j]<A[i]; } int dfs(int cur) //深搜,记忆化搜索 { if( d[cur] > 0) return d[cur];//已经找过的直接输出 d[cur] = 1; //没找的先付初值1,然后深搜寻找 for(int i=1;i<=n;i++) { if( map[cur][i] && d[cur] < dfs(i)+1) { d[cur] = dfs(i)+1; } } return d[cur]; } void out(int i) //反向追踪找到选取图形的标号 { for(int j=1;j<=n;j++) { if( map[i][j] && d[i] == d[j]+1) { out(j); break; } } cout << A[i]<< " ";//放在上面是倒着输出,下面是睁着输出 } int main(){ for(;cin>>n && n;){ int i,j; for(i=1;i<=n;i++){ //输入 cin>>A[i]; } memset(map,0,sizeof(map)); //构造一个ok关系的0-1邻接矩阵 for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(ok(i,j)) map[i][j]=1; memset(d,0,sizeof(d)); //深搜记忆化完成d[]表 for(i=1;i<=n;i++){ dfs(i); } int max=0,ds; //找出d[]的最大值并用ds存储尾链位置 for(i=1;i<=n;i++){ if(max<d[i]){ max=d[i]; ds=i; } } cout<<max<<' '; out(ds);cout<<' '; } return 0; }
solve two:正向求解,边输边计算d[]的值
#include<iostream> #include<algorithm> using namespace std; #define maxn 1000+5 #define INF 1<<31 int A[maxn],d[maxn],n; void out(int i) //反向追踪找到选取图形的标号 { for(int j=1;j<=n;j++) { if(i>j && A[i]>A[j] && d[i] == d[j]+1) { out(j); break; } } cout <<A[i]<< " "; } int main(){ int i,j; while(cin>>n){ memset(d,0,sizeof(d)); int maxx=-INF,ds; for(i=1;i<=n;i++){ cin>>A[i]; int max=-INF; for(j=1;j<i;j++) if(A[i]>A[j] && max<d[j]) max=d[j]; d[i]=(max==-INF ? 1: max+1); if(maxx<d[i]){maxx=d[i];ds=i;} } cout<<maxx<<' '; out(ds); cout<<' '; } }