航线——线性dp
题目描述
Palmia 河在某国从东向西流过,并把该国分为南北两个部分。河的两岸各有 n
个城市,且北岸的每一个城市都与南岸的某个城市是友好城市,而且对应的关系是一一对应的。现在要求在两个友好城市之间建立一条航线,但由于天气的关系,所有航线都不能相交,因此,就不可能给所有的友好城市建立航线。
问题:当城市个数和友好关系建立之后,选择一种修建航线的方案,能建最多的航线而不相交。(若有多种方案,修建航线最多且城市数量相同,选择从前到后城市标号字典序小的那种方案.)
输入格式
输入由若干行组成,第一行有一个整数,n(1≤n≤10000)
;表示城市数。第2
至n+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\n%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\n",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\n",ans); Print(la);//由la递归输出 return 0; }