所谓DAG就是有向无环图,利用关键路径的做法有些复杂。
我们建立一个数组dp[n+1], dp[i]代表从这个结点出发的最长路径, 那么要求出dp[i], 我们只要求出从i出发的下一结点的dp[j], 使得dp[i] = max(dp[i], dp[j] + G[i][j]), 这就是它的状态转移方程.
可是dp[j] 怎么求呢? 同理,我们如果求出它的后一个结点的dp[k], 我们就可以相应求出dp[j].
经过上面的分析, 不难发现, 整个的过程可以用递归实现. 当i结点的出度为0时, 我们就可以给出dp[i] = 0, 从而实现整个问题的求解.
一、固定起点求最长路径
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int len=101;
struct g {
int v;
int w;
};
vector<g>G[len];
int dp[len];
bool visit[len];
int choice[len];//存路径
int DP(int i) {
if(visit[i])
return dp[i];
visit[i]=true;
for(int j=0; j < G[i].size(); j++) {
if(dp[i]<DP(G[i][j].v)+G[i][j].w) {//逆拓扑求最长路径
dp[i]=DP(G[i][j].v)+G[i][j].w;
choice[i]=G[i][j].v;//存后继节点
}
}
return dp[i];
}
void printPath(int i) {
cout<<i;
while(choice[i]!=-1) {
cout<<"->"<<choice[i];
i=choice[i];
}
}
int main() {
int n,m,start;
cin>>n>>m>>start;
fill(dp,dp+len,0);
fill(visit,visit+len,false);
fill(choice,choice+len,-1);
for(int i = 0; i < m; i++) {
int x,y,w;
cin>>x>>y>>w;
g t;
t.v=y;
t.w=w;
G[x].push_back(t);
}
cout<<DP(start)<<endl;
printPath(start);
return 0;
}
二、国定终点求最长路径
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int len=101;
int Grap[len][len];
int dp[len];
bool visit[len];
int choice[len];//存路径
int n,m,end;
int DP(int i) {
if(visit[i])
return dp[i];
visit[i]=true;
for(int j=1; j <= n; j++) {
if(Grap[j][i]!=-1) {
if(dp[i]<DP(j)+Grap[j][i]) {
dp[i]=DP(j)+Grap[j][i];
choice[i]=j;
}
}
}
return dp[i];
}
void printPath(int i) {
cout<<i;
while(choice[i]!=-1) {
cout<<"->"<<choice[i];
i=choice[i];
}
}
int main() {
cin>>n>>m>>end;
fill(dp,dp+len,0);
fill(visit,visit+len,false);
fill(choice,choice+len,-1);
fill(Grap[0],Grap[0]+len*len,-1);
for(int i = 0; i < m; i++) {
int x,y,w;
cin>>x>>y>>w;
Grap[x][y]=w;
}
cout<<DP(end)<<endl;
printPath(end);
return 0;
}