UVA103DAG上最长路径+字典序输出

题目描述:

给定n维的m个物品,按照各维长度严格递增的排序,求最长的序列,并按照字典序输出。

例如n=4,(1 2 3 4)之后是(2,3,4,5)就可以。

思维过程:

《入门经典》上DAG模型。

枚举状态结点时,出现了思维误区。想要把n维的n个长度滚动成n种状态点。

上述考虑固然可以,但是不是n种状态点,因为是按顺序排列,所以是n!种,然而n《=30。

后来想到了贪心的优化,我们的重点是一个能嵌套到另一个种,所以我们将变长从大到小排序。

例如:a1<=a2<=a3<=a4<=a5

          b1<=b2<=b3<=b4<=b5

假设把b3换到b2之前,如果b2>a3,那么固然b3>a2,所以排序后比较能保证能放就一定能放进

算法分析:

1、每个状态抽象成一个点,既求有向无环图上求最长路径

2、没有终点,故枚举每个终点,结束点是每一个状态自成单点,既d[i]=0;

3、为输出字典序,故枚举的是dp(i)以i为终点。

4、调试的时候可以输出所有dp,方便模拟状态转移

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#define maxn 310//最多的状态数
using namespace std;
int d[maxn];
int G[maxn][maxn];
int m,n;
struct Node{
    int a[15];//各个维度的长度
}node[maxn];
void print_path(int p){
    if (d[p]>1) printf("%d ",p);else printf("%d
",p);
    for(int i=1;i<=m;i++)
        if (d[i]+1==d[p] && G[p][i]==1) {print_path(i);break;}
}
void readin(){
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++)
            scanf("%d",&node[i].a[j]);
    sort(node[i].a+1,node[i].a+n+1);
    }
}
void builtG(){
    memset(G,0,sizeof(G));
    for(int i=1;i<=m;i++){
        for(int j=1;j<=m;j++){
            if (i==j) continue;
            int mark=1;
            for(int k=1;k<=n;k++)
            if (node[i].a[k]>=node[j].a[k]){mark=0;break;}
            if (mark) G[i][j]=1;
        }
    }
}
int dp(int i){
    int &ans=d[i];
    if (ans>0) return ans;
    ans=1;
    for(int j=1;j<=m;j++) if (G[i][j]) ans=max(ans,dp(j)+1);
    return ans;
}
void slove(){
    readin();
    builtG();
    memset(d,0,sizeof(d));
    int ans=-1;int p=-1;
    for(int i=1;i<=m;i++){
        int k=dp(i);
        if (ans<k) {ans=k;p=i;}
    }
    printf("%d
",ans);
    print_path(p);
    return ;
}
int main(){
    while(~scanf("%d%d",&m,&n)) slove();
    return 0;
}

  

原文地址:https://www.cnblogs.com/little-w/p/3446784.html