航线——线性dp

题目描述

Palmia 河在某国从东向西流过,并把该国分为南北两个部分。河的两岸各有 n 个城市,且北岸的每一个城市都与南岸的某个城市是友好城市,而且对应的关系是一一对应的。现在要求在两个友好城市之间建立一条航线,但由于天气的关系,所有航线都不能相交,因此,就不可能给所有的友好城市建立航线。

问题:当城市个数和友好关系建立之后,选择一种修建航线的方案,能建最多的航线而不相交。(若有多种方案,修建航线最多且城市数量相同,选择从前到后城市标号字典序小的那种方案.)

输入格式

输入由若干行组成,第一行有一个整数,n(1≤n≤10000);表示城市数。第2n+1行依次是南岸城市的北岸友好城市编号。

输出格式

输出共两行,第一行是建立航线的数量。第二行是建立航线的北岸城市编号。

样例

样例输入

14
13
7
9
16
38
24
37
18
44
19
21
22
63
15

样例输出

8
7 9 16 18 19 21 22 63

怎么看着这么像友好城市呢...(如果不输出路径的话
可为什么放在区间dp里???迷惑
反正我按友好城市 不下降子序列 做的。
路径的话保存转到 i 的编号即可。最后递归输出。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 1e4+3;

int a[MAXN], n, pa[MAXN], ans, tot,la, f[MAXN];

void Print(int x){
    if(pa[x]!=-1){
        Print(pa[x]); printf("%d ",a[x]);
    }else{
        printf("%d ",a[x]);
    }
}
int main(){
    scanf("%d",&n); memset(pa,-1,sizeof(pa));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    if(n==1){
        printf("1
%d",a[1]); return 0;
    }
    for(int i=1;i<=n;i++){
        f[i]=1; 
        for(int j=1;j<i;j++){
            if(a[i]>=a[j] && f[i]<f[j]+1) {f[i]=f[j]+1;pa[i]=j;}
            if(ans<f[i]) ans=f[i],la=i;
        }
    }
    printf("%d
",ans);
    Print(la);
    return 0;
}


完了?

完...
蛋。

总有一个点过不去...
如果输入全倒序呢?
显然在下面这个循环中,如果 a[i+1]<a[i]的话,里面的if语句是不会执行的。那最后 la 也就是最初的 0,是没有办法输出路径的。
for(int i=1;i<=n;i++){
        f[i]=1; 
        for(int j=1;j<i;j++){
            if(a[i]>=a[j] && f[i]<f[j]+1) {f[i]=f[j]+1;pa[i]=j;}
            if(ans<f[i]) ans=f[i],la=i;
        }
    }

于是需要初始化 la。当对任一 i 都有 a[i+1]<a[i] 的时候,我们只能建立一条航线。那这条航线肯定就是从 1 号城市到 对岸的最后一个城市。这时,我们就可以得到 100 了。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 1e4+3;

int a[MAXN], n, pa[MAXN], ans, tot,la, f[MAXN];

void Print(int x){
    if(pa[x]!=-1){//如果x有父亲
        Print(pa[x]); printf("%d ",a[x]);//先输出父亲,再输出x
    }else{//x没父亲(x是第一个)
        printf("%d ",a[x]);//直接输出
    }
}
int main(){
    ans=1; la=1; //CaO...beyond expression...mamaipi...需要考虑特殊情况
    scanf("%d",&n); memset(pa,-1,sizeof(pa));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n;i++){
        f[i]=1;
        for(int j=1;j<i;j++){
            if(a[i]>=a[j] && f[i]<f[j]+1){//不下降
                f[i]=f[j]+1;
                pa[i]=j;//记录是由谁到i的
            }
            if(ans<f[i]) ans=f[i],la=i;//记录最后一个,以便递归输出
        }
    }
    printf("%d
",ans);
    Print(la);//由la递归输出
    return 0;
}
 
原文地址:https://www.cnblogs.com/Siegfried-L/p/12864085.html