2019ICPC銀川區域賽-H.Delivery Route( spfa優化 或 強連通分量+拓排+dij)

題目大意給一個n個點,x條雙向邊,y條單向邊的圖,同時雙向邊權全爲正,單向邊權有可能爲負,且保證單向邊不會出現在環中。求從點s分別到1~ n的最短距離。

       由於有負邊,不能直接用dij,而裸的spfa又會被卡上天,所以需要考慮下其它做法。

       強連通分量+拓排+dij。由於負權邊不會出現在環中,所以可對圖進行縮點,對每個強連通分量跑一遍dij,同時按拓撲序更新後面強連通分量點距離的初始值。

      同時由於邊權總和不是很大或數據沒卡到   spfa + SLF容錯優化選擇合適的容錯值  sqrt(sum)/800 ~ sqrt(sum)/50  在計蒜客上也可以過這道題(逃。。。。

//強連通分量+拓排+dij  61ms
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<vector>
using namespace std;
const int N=1e6;
int p[N],w[N],head[N],nex[N],e=1;
void add(int a,int b,int c){
    p[e]=b;
    nex[e]=head[a];
    head[a]=e;
    w[e++]=c;
}

stack<int>s;
int low[100010],dfn[100010],cnt=0,S=0,vis[100010],bel[100010];
vector<int>A[100010];
void tarjan(int u){
    int i,v;
    low[u]=dfn[u]=++cnt;
    vis[u]=1;
    s.push(u);
    for(i=head[u];i;i=nex[i]){
        v=p[i];
        if(dfn[v]==0){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        S++;
        bel[u]=S;
        A[S].push_back(u);
        vis[u]=0;
        for(;s.top()!=u;s.pop()){
            bel[s.top()]=S;
            A[S].push_back(s.top());
            vis[s.top()]=0;
        }
        s.pop();
    }
}

vector<int>g[100010];
int B[100010];
int dfs(int u){
    vis[u]=2;
    int i,v;
    for(i=0;i<g[u].size();i++){
        v=g[u][i];
        if(vis[v]==2) return 0;
        if(vis[v]==0&&dfs(v)==0) return 0;
    }
    cnt++;
    B[cnt]=u;
    vis[u]=1;
    return 1;
}

struct Q{
    int id,v;
    int operator <(const Q &a)const{
        return v>a.v;
    }
};
priority_queue<Q>q;
int dp[100100];
void dij(int s){
     int i,k,v;
     for(i=0;i<A[s].size();i++)  q.push(Q({A[s][i],dp[A[s][i]]}));
     Q u;
     for(;q.size();q.pop()){
         u=q.top();
         if(vis[u.id]) continue;
         vis[u.id]=1;
         for(i=head[u.id];i;i=nex[i]){
            v=p[i];
            if(bel[v]==bel[u.id]&&dp[v]>dp[u.id]+w[i]&&vis[v]==0){
                dp[v]=dp[u.id]+w[i];
                q.push(Q({v,dp[v]}));
            }
         }
     }
}

int main(){
    int i,j,k,n,x,y,s,a,b,c;
    scanf("%d%d%d%d",&n,&x,&y,&s);
    for(i=1;i<=x;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    for(i=1;i<=y;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }

    tarjan(s);
    for(i=1;i<=n;i++){
        if(dfn[i]==0) continue;
        for(j=head[i];j;j=nex[j]){
            a=p[j];
            b=bel[i];
            c=bel[a];
            if(b!=c) g[b].push_back(c);
        }
    }

    memset(vis,0,sizeof(vis));
    cnt=0;
    dfs(bel[s]);

    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++) dp[i]=2e9;
    dp[s]=0;
    for(k=cnt;k;k--){
        a=B[k];
        dij(a);
        for(i=0;i<A[a].size();i++){
            b=A[a][i];
            for(j=head[b];j;j=nex[j]){
                c=p[j];
                if(bel[c]!=bel[b]) dp[c]=min(dp[c],dp[b]+w[j]);
            }
        }
    }
    for(i=1;i<=n;i++){
        if(dp[i]==2e9) printf("NO PATH\n");
        else printf("%d\n",dp[i]);
    }
    return 0;
}

 

//spfa + SLF容錯優化 480ms
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<set>
#include<queue>
using namespace std;
const int N=1e6;
int p[N],w[N],head[N],nex[N],e=1;
void add(int a,int b,int c){
    p[e]=b;
    nex[e]=head[a];
    head[a]=e;
    w[e++]=c;
}

long long dp[100010],val=0;
int q[20000010],l,r,vis[100010];
void bfs(int s,int n){
     int i,u,v;
     for(i=1;i<=n;i++) dp[i]=1e18;
     dp[s]=0;
     l=r=1e7;
     q[l]=s;
     vis[s]=1;
     while(l<=r){
        u=q[l];
        vis[u]=0;
        l++;
        for(i=head[u];i;i=nex[i]){
            v=p[i];
            if(dp[v]>dp[u]+w[i]){
                dp[v]=dp[u]+w[i];
                if(vis[v]==0){
                    if(l>r) q[++r]=v;
                    else{
                        if(dp[q[l]]+val<dp[v]) q[++r]=v;
                        else q[--l]=v;
                    }
                    vis[v]=1;
                }
            }
        }
     }
     for(i=1;i<=n;i++){
        if(dp[i]==1e18) printf("NO PATH\n");
        else printf("%lld\n",dp[i]);
     }
}

int main(){
    int i,n,x,y,s,a,b,c;
    scanf("%d%d%d%d",&n,&x,&y,&s);
    for(i=1;i<=x;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
        val+=2*c;
    }
    for(i=1;i<=y;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        val+=c;
    }
    val=sqrt(val)/100;
    bfs(s,n);
    return 0;
}

      

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章