最长路径问题
题目
给定一个正权有向无环图和图中的两个顶点,请编写程序找出这两个顶点间的最长路径,若两点间存在多条最长路径,则输出字典序最小者。假定图中包含n个顶点,编号为0至n-1。
注:字典序,即对象在字典中的顺序。对于两个数字序列,从第一个数字开始比较,当某一个位置的数字不同时,该位置数字较小的序列,字典序较小,例如1 2 3 9比1 2 4 5小,1 2 8 9比1 2 10 3小。
- 输入格式:
输入第一行为3个正整数n和e,分别为图的顶点数和边数,均不超过50。接下来e行表示每条边的信息,每行为3个整数a、b、c,其中a和b表示该边的端点编号,c表示权值。各边并非按端点编号顺序排列。接下来1行为两个整数s和t,表示两个顶点编号。
- 输出格式:
输出顶点s到顶点t的字典序最小最长路径,路径中顶点编号用“->”间隔。如s和t不连通,则输出“none”。
输入样例:
4 4
0 1 1
1 2 1
0 3 1
3 2 2
0 2
输出样例:
0->3->2
代码长度限制
16 KB
时间限制
100 ms
内存限制
64 MB
思路
这题的正规解法:是有向无环图,先拓扑排序,再用动态规划求解。
不能使用dijkstra算法,因为dijk算法不能修改已经探索过一次的节点,但是我们可能会找到一条更长的路径来到达某个结点,这就会产生矛盾。例如这次加入结点u,最长路为10,下次有可能加入一个结点v,使得 u通过v到源点的距离大于10,但由于u在之前已经被加入到集合中,无法再更新,导致结果是不正确的。
如果取反用dijkstra求最短路径呢,记住,dijkstra不能计算有负边的情况。。。
但是这题又需要按照字典序来得到最恰当的那条路径,很烦人。因为我的深度优先算法dfs运用的不是很理想,不太会回溯,所以就另辟蹊径了。
首先看到这题最多只有50个结点,那有向边的数量就超不过2500条,对于这个小量级的数据,我可以在一开始就将它们按照顺序排好,起始节点小的优先,终点节点小的次优先,因我我使用的建图方法是链式头插法建图,对于同一个节点的所有边,遍历顺序是和插入顺序相反的。所以我只要在拓扑排序的过程中,贪心判断规则改为>=,就可以保证每个点保存的last节点都是最小字典序的。
这个方法应该是存在漏洞的,但是好歹也是AC了,哈哈哈
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 55
#define maxm 2505
using namespace std;
int tot,n,m,s,e,flag;
int len[maxm];
int v[maxm];
int head[maxn];
int vis[maxn];
int nxt[maxm];
int maxlen[maxn];
int in[maxn];
int out[maxn];
int last[maxn];
int depth[maxn];
int deep;
queue<int> q;
struct EDGE{
int u;
int v;
int len;
}edge[maxm];
bool comp(const struct EDGE e1,const struct EDGE e2){
if(e1.u<e2.u){
return true;
}else if(e1.u==e2.u){
if(e1.v<e2.v){
return true;
}
}
return false;
}
void init(){
for(int i=0;i<n;i++){
last[i]=-1;
}
}
void ins(int start,int end,int l){
++tot;
len[tot]=l;
v[tot]=end;
nxt[tot]=head[start];
head[start]=tot;
}
void topo(){
while(!q.empty()){
int t = q.front();
q.pop();
vis[t]=1;
for(int i=head[t];i!=0;i=nxt[i]){
int j=v[i];
if(j==e){
flag=1;
}
if(!vis[j]){
if(maxlen[t]+len[i]>=maxlen[j]){
maxlen[j]=maxlen[t]+len[i];
last[j]=t;
depth[j]=depth[t]+1;
}
in[j]--;
if(in[j]==0){
q.push(j);
}
}
}
}
}
void print(){
for(int i=0;i<n;i++){
cout<<i<<" maxlen: "<<maxlen[i]<<" last:"<<last[i]<<" depth:"<<depth[i]<<endl;
}
}
void getList(int node){
if(node==-1) return;
getList(last[node]);
if(node==e)
cout<<node;
else
cout<<node<<"->";
}
int main(){
cin>>n>>m;
init();
int start,end,l,ecnt=0;
for(int i=0;i<m;i++){
cin>>start>>end>>l;
edge[++ecnt].u=start;
edge[ecnt].v=end;
edge[ecnt].len=l;
}
sort(edge+1,edge+1+ecnt,comp);
for(int i=1;i<=ecnt;i++){
ins(edge[i].u,edge[i].v,edge[i].len);
in[edge[i].v]++;
out[edge[i].u]++;
}
cin>>s>>e;
q.push(s);
depth[s]=1;
res[++deep] = s;
topo();
//print();
if(!flag){
cout<<"none";
}else{
getList(e);
// cout<<e;
}
}