有向无环图的最长路简单求法搜索博客:点击打开链接
题意:给出n个点,m条边,这是一个有向图,然后问你能不能找一个最长路,那么就有一个问题如果途中有环呢,那么我们就得先用tarjan缩点,然后变成了有向无环图,我们就可以用搜索来找到这条路。
搜索时因为搜索没有算最开始进去的那个点,并且我们知道缩点后整个图会变成一个有向无环图,那么必定有入度为0的点,然后我们找到这个点,计算过后加上这个点才是答案,还有个问题,因为tarjan是基于搜索的算法,而缩点就是在回溯是完成的,那么它形成新的图会使这样的,3-->2-->1,这里的1 2 3指的是缩点后的点,比如这么一组样例
8 9
1 2
2 3
3 4
4 5
5 2
3 6
6 7
7 8
8 6
缩点以后就变成了3:1; 2:2,3,4,5 1:6,7,8 表达的不是很清楚,希望大家能理解,虽然最后加的数据就是入度为0的那个点,但是这样让我们能更好的理解代码,反正我找bug的过程中发现自己更了解tarjan和搜索了...
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; struct node { int v; int nextt; } e[200005],ee[200005];//e是用来存缩点以前的图,ee是缩点以后的图 int first[100005],low[100005],dfn[100005],vis[100005],firstt[100005];//first是缩点前,firstt缩点后 int sta[100005],staa[100005],dp[100005],vv[100005];//vv用来找没有入度的边,dp[i]存从i点出发最远能走多少,sta记录每个缩点中的点,staa记录每个缩点里的点的个数 int r,k,cnt,sum,rr; void init() { memset(first,-1,sizeof(first)); memset(firstt,-1,sizeof(firstt)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(sta,0,sizeof(sta)); memset(staa,0,sizeof(staa)); memset(dp,0,sizeof(dp)); memset(vv,0,sizeof(vv)); r=0; k=0; rr=0; cnt=1; sum=0; } void add(int u,int v) { e[r].v=v; e[r].nextt=first[u]; first[u]=r++; } void add1(int u,int v) { ee[rr].v=v; ee[rr].nextt=firstt[u]; firstt[u]=rr++; } void tarjan(int u) { vis[u]=1; low[u]=dfn[u]=cnt++; sta[++k]=u; for(int i=first[u]; i!=-1; i=e[i].nextt) { int v=e[i].v; if(vis[v]==0) tarjan(v); if(vis[v]==1) low[u]=min(low[v],low[u]); } if(dfn[u]==low[u]) { sum++; do { vis[sta[k]]=2; staa[sum]++; low[sta[k]]=sum; } while(sta[k--]!=u); } } int dfs(int i)//有点毛病,每次计算都没有带上最开始的i { if(dp[i]>0) return dp[i]; for(int j=firstt[i];j!=-1;j=ee[j].nextt) { int v=ee[j].v; dp[i]=max(dp[i],dfs(v)+staa[v]); } return dp[i]; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { init(); int a,b; for(int i=0; i<m; i++) { scanf("%d%d",&a,&b); add(a,b); } for(int i=1; i<=n; i++) { if(vis[i]==0) tarjan(i); } for(int i=1; i<=n; i++) for(int j=first[i]; j!=-1; j=e[j].nextt) { int v=e[j].v; if(low[i]!=low[v]) { add1(low[i],low[v]); vv[low[v]]++; } } int ii;//入度为0的点 for(int i=1;i<=sum;i++) { if(vv[i]==0) dfs(i),ii=i; } int maxx=-1; for(int i=1;i<=sum;i++) { if(maxx<dp[i]) maxx=dp[i]; } printf("%d\n",maxx+staa[ii]); } }