DAG的最短路

题目:https://ac.nowcoder.com/acm/contest/329/B

分析:由于带负权,肯定不能用Dijkstra,用spfa可高效解决,但是特殊 DAG 的性质使得 SPFA 算法无法在规定的时间限内求解出答案,此时由DAG的拓扑序列可以很好解决该问题。

因此,放弃vis数组,以拓扑序列来入队

Ac code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
const ll INF=1e10;
vector<pair<int,ll> >edge1[maxn];
vector<pair<int,ll> >edge2[maxn];
ll dis1[maxn],dis2[maxn];
int dg1[maxn],dg2[maxn];
int n;
ll Spfa(int s,ll dis[],int dg[],vector<pair<int,ll> >edge[])
{
    queue<int>q;
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++) dis[i]=INF;
    dis[s]=0;
    for(int i=1;i<=n;i++) if(dg[i]==0) q.push(i);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<edge[u].size();i++){
            int v=edge[u][i].first;
            ll w=edge[u][i].second;
            dis[v]=min(dis[v],dis[u]+w);
            if(--dg[v]==0)
                q.push(v);
        }
    }
    return max(0ll,dis[n]);
}
int main()
{
    int t,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++) edge1[i].clear(),edge2[i].clear();
        int u,v;
        ll w0,w1,w2;
        for(int i=1;i<=m;i++){
           scanf("%d%d%lld%lld%lld",&u,&v,&w0,&w1,&w2);
           edge1[u].push_back(make_pair(v,-w1+w0)),edge2[u].push_back(make_pair(v,-w2+w0));
           dg1[v]++,dg2[v]++;
        }
        ll ans1=Spfa(1,dis1,dg1,edge1);
        ll ans2=Spfa(1,dis2,dg2,edge2);
        if(ans1<ans2){
            puts("cnznb!!!");
            printf("%lld\n",ans2-ans1);
        }
        else if(ans1>ans2){
            puts("rip!!!");
            printf("%lld\n",ans1-ans2);
        }
        else puts("oof!!!");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shaohang_/article/details/86668443
今日推荐