拓扑求DAG最长路

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define maxn 1000000
using namespace std;
int n,m;
struct Edge{//存边 
    int next;
    int to;
    int dis;
}edge[maxn];
queue<int> q;//拓扑排序要用队列 
int head[maxn];
int wei[maxn];//点的最大值 
int deg[maxn];//点的入度 
int a,b,p,num,x;
void add(int u,int v,int d){
    edge[++num].next=head[u];
    edge[num].to=v;
    edge[num].dis=d;
    head[u]=num;
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a,&b,&p);
        add(a,b,p);
        deg[b]++;
    }
    memset(wei,-0x7f,sizeof(wei));//刚开始的时候,要把所有出了一以外的赋成负无穷,这样保证是从1开始 
                                  //这个数据应该是比较水的,没有负边权
                                  //要是有的话,就在每个经过的点上打个标记来判断有没有一条路是到达n的 
    for(int i=1;i<=n;i++){
        if(!deg[i])q.push(i);
        if(i==1)wei[i]=0;
        else wei[i]=-maxn;
    }
    while(!q.empty()){//拓扑排序 
        x=q.front();
        q.pop();
        for(int i=head[x];i;i=edge[i].next){ 
            deg[edge[i].to]--;//入度减1 
            wei[edge[i].to]=max(wei[edge[i].to],wei[x]+edge[i].dis);
            /*更新是这样的:
                这个点的值最大=max(这个点原来的值,他的前驱节点+连接前驱和他自己的边的值) 
            */ 
            if(deg[edge[i].to]==0){//若入度为0则又入队 
                q.push(edge[i].to); 
            }
        }
    }
    if(wei[n]<0){//为什么不取等?因为有可能所有边的权值都是0  
        printf("%d",-1);
        return 0;
    }
    printf("%d",wei[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/SUMMER20020929/p/9843075.html