題目大意:給一個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;
}