[USACO11JAN]Roads and Planes

嘟嘟嘟

这道题他会卡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
") : (write(dis[i]), enter);
105     return 0;
106 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9600698.html