http://acm.timus.ru/problem.aspx?space=1&num=1651
题意:给出链上点的顺序 要求找一条子链 满足三个条件
1,起点和终点和原链一样
2,边的顺序和原始顺序一致
3,最短
思路:
如果去掉第二个条件的话 就变成了最简单的最短路了 由于第二个条件的限制 要按给的边的顺序依次更新
然后重要的就是记录路径
代码及其注释:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<vector> #include<map> #include<queue> #include<stack> #include<cmath> #define LL long long //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int INF=0x3f3f3f3f; const int N=10005; vector<int>dist[N];//到节点 i 的最优距离 如果有更新就不断在后面累计 vector<int>f1[N];//到节点 i 第 j 个最优更新 的上一个节点 vector<int>f2[N];//到节点 i 第 j 个最优更新 的上一个节点的第几个更新 int a[N*10];//注意大小 void sovle(int n) { dist[a[1]].push_back(0); f1[a[1]].push_back(-1); f2[a[1]].push_back(-1); for(int i=2;i<=n;++i) { int l1=dist[a[i]].size(); int l2=dist[a[i-1]].size(); if((l1==0)||(dist[a[i]][l1-1]>dist[a[i-1]][l2-1]+1))//可继续更新 { dist[a[i]].push_back(dist[a[i-1]][l2-1]+1);//在后面累计 f1[a[i]].push_back(a[i-1]);//记录路径 f2[a[i]].push_back(l2-1);//记录路径 } } } void dfs(int x,int k) { if(f1[x][k]!=-1) dfs(f1[x][k],f2[x][k]); cout<<x<<" "; } int main() { //freopen("data.txt","r",stdin); int n; cin>>n; for(int i=1;i<=n;++i) cin>>a[i]; if(a[1]==a[n]) {cout<<a[1]<<endl;return 0;}//首尾一样的情况 sovle(n); dfs(a[n],dist[a[n]].size()-1); cout<<endl; return 0; }