这道题他会卡spfa,不过据说加SLF优化后能过,但还是讲讲正解吧。
题中有很关键的一句,就是无向边都是正的,只有单向边可能会有负的。当把整个图缩点后,有向边只会连接在每一个联通块之间(因为图中没有环),而且缩点后的图一定是一个DAG,DAG的最短路就可以拓扑排序后直接求出最短路。
因此,对于每一个联通块内,我们可以dijkstra跑最短路:除了常规的更新以外,每一次跑的时候都要先把这个块内的所有点都放进优先队列中,因为有的点可能已经从别的联通块更新了。然后对于一条边u->v,如果u,v在一个联通块内,就正常更新,否则是更新dis[y],不把他放进队列,而是把y所在的联通块的入度--,如果为0,就放进拓扑序的队列中。
直到拓扑序的队列空。
对于有些走不到的点,可能在INF上加上了一个负数,因此最后判断是否能走到不能dis[i] = INF?,我就是稍微把这个上界放小一点,但又大于最远的dis,于是判断dis[i] > INF / 2?。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 2.5e4 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 26 if(last == '-') ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) x = -x, putchar('-'); 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + '0'); 34 } 35 36 int n, r, p, s; 37 vector<int> v[maxn], c[maxn]; 38 vector<int> blo[maxn]; 39 40 int col[maxn], cnt = 0; 41 void dfs(int now) 42 { 43 col[now] = cnt; blo[cnt].push_back(now); 44 for(int i = 0; i < (int)v[now].size(); ++i) 45 if(!col[v[now][i]]) dfs(v[now][i]); 46 } 47 48 int in[maxn]; 49 queue<int> topo; 50 51 #define pr pair<int, int> 52 #define mp make_pair 53 int dis[maxn]; 54 bool inq[maxn]; 55 void dijkstra(int bl) 56 { 57 Mem(inq); 58 priority_queue<pr, vector<pr>, greater<pr> > q; 59 for(int i = 0; i < (int)blo[bl].size(); ++i) q.push(mp(dis[blo[bl][i]], blo[bl][i])); 60 while(!q.empty()) 61 { 62 int now = q.top().second; q.pop(); 63 if(inq[now]) continue; 64 inq[now] = 1; 65 for(int i = 0; i < (int)v[now].size(); ++i) 66 { 67 int to = v[now][i]; 68 if(col[now] == col[to]) 69 { 70 if(dis[to] > dis[now] + c[now][i]) 71 { 72 dis[to] = dis[now] + c[now][i]; 73 q.push(mp(dis[to], to)); 74 } 75 } 76 else 77 { 78 if(dis[to] > dis[now] + c[now][i]) dis[to] = dis[now] + c[now][i]; 79 if(!--in[col[to]]) topo.push(col[to]); 80 } 81 } 82 } 83 } 84 85 int main() 86 { 87 n = read(); r = read(); p = read(); s = read(); 88 for(int i = 1; i <= r; ++i) 89 { 90 int x = read(), y = read(), co = read(); 91 v[x].push_back(y); c[x].push_back(co); 92 v[y].push_back(x); c[y].push_back(co); 93 } 94 for(int i = 1; i <= n; ++i) if(!col[i]) ++cnt, dfs(i); 95 for(int i = 1; i <= p; ++i) 96 { 97 int x = read(), y = read(), co = read(); 98 v[x].push_back(y); c[x].push_back(co); 99 if(col[x] != col[y]) in[col[y]]++; 100 } 101 for(int i = 0; i <= cnt; ++i) if(!in[i]) topo.push(i); 102 for(int i = 1; i <= n; ++i) dis[i] = INF; dis[s] = 0; 103 while(!topo.empty()) dijkstra(topo.front()), topo.pop(); 104 for(int i = 1; i <= n; ++i) dis[i] > (INF >> 1) ? printf("NO PATH\n") : (write(dis[i]), enter); 105 return 0; 106 }View Code