1. 程式人生 > >[bzoj1073][SCOI2007]kshort【K短路】

[bzoj1073][SCOI2007]kshort【K短路】

【題目連結】
  https://www.lydsy.com/JudgeOnline/problem.php?id=1073
【題解】
  重點:我沒有cheat
  題意非常簡單,就是求ab的第k大簡單路徑。普通的A*演算法並沒有可靠的複雜度保證。這裡介紹一種有複雜度保證的Yen演算法。
  先給一個簡單的概括:首先求出ab的最短路,加入優先佇列中。然後考慮每次將一條最短路上的邊刪除,然後求出次短路並加入優先佇列。重複此操作直到求出第k條路徑。
  具體來講一下尋找新路徑的操作:
  我們定義偏離節點為從ab可以改變的第一個點。
  那麼從這個點及其之後的節點,我們考慮將它的入邊刪去。
  不妨記這個點為

now,記連向它的點為pre,一條邊的邊權為votei,j
  首先求出每個點到b的距離,記作disi,然後在pre的所有出邊中,找到一個點j使得votepre,j+disj>votepre,now+disnowvotepre,j+disj最小。
  然後將這條路徑的偏離節點設為j比將其加入佇列。
  但這樣尋找的路徑可能會經過重複的點,有一個解決的方案:再求dis時可以將到偏離節點之前的點都設為不可用。
  時間複雜度O(KNMlogM)
【程式碼】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [bzoj1073]
    Points :    K-th shortest road -- Yen algorithm 
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       51
# define K 210 using namespace std; typedef vector <int> vt; int read(){ int tmp = 0, fh = 1; char ch = getchar(); while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); } while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); } return tmp * fh; } struct Node{ int vote, id; vector <int> rd, d; }now, nex; struct Edge{ int data, next, vote; }e[N * N * 2]; vt rd[K], eg[N], vg[N]; priority_queue <Node> hp; int n, m, k, S, T, dis[N], use[N], tag[N], q[N], head[N], frm[N], place; set <vt> mp; void build(int u, int v, int w){ e[++place].data = v; e[place].next = head[u]; head[u] = place; e[place].vote = w; } bool operator < (Node x, Node y){ if (x.vote > y.vote) return true; if (x.vote < y.vote) return false; for (unsigned j = 0; ; j++){ if (j == y.rd.size() && j != x.rd.size()) return true; if (j == x.rd.size() && j != y.rd.size()) return false; if (j == y.rd.size() && j == x.rd.size()){ if (x.id > y.id) return true; else return false; } if (x.rd[j] > y.rd[j]) return true; if (x.rd[j] < y.rd[j]) return false; } } bool operator < (vt x, vt y){ for (unsigned j = 0; ; j++){ if (j == y.size()) return true; if (j == x.size()) return false; if (x[j] > y[j]) return true; if (x[j] < y[j]) return false; } } void spfa(int T){ memset(dis, inf, sizeof(dis)); dis[T] = 0, q[1] = T; memset(use, 0, sizeof(use)); int pl = 1, pr = 1; use[T] = true; while (pl <= pr){ int x = q[(pl++) % n]; for (int ed = head[x]; ed != 0; ed = e[ed].next) if (tag[e[ed].data] == false){ if (dis[e[ed].data] > dis[x] + e[ed].vote || (dis[e[ed].data] == dis[x] + e[ed].vote && x < frm[e[ed].data])){ dis[e[ed].data] = dis[x] + e[ed].vote; frm[e[ed].data] = x; if (use[e[ed].data] == false){ use[e[ed].data] = true; q[(++pr) % n] = e[ed].data; } } } use[x] = false; } } bool cmp(int x, int vx, int y, int vy){ return vx < vy || (vx == vy && x < y); } int main(){ // freopen(".in", "r", stdin); // freopen(".out", "w", stdout); n = read(), m = read(), k = read(), S = read(), T = read(); for (int i = 1; i <= m; i++){ int u = read(), v = read(), w = read(); build(v, u, w); eg[u].push_back(v); vg[u].push_back(w); } spfa(T); bool flag = true; nex.id = 0, nex.vote = dis[S]; int p = S, tot = 0; nex.rd.push_back(S), nex.d.push_back(0); while (p != T){ nex.rd.push_back(frm[p]); nex.d.push_back(tot += dis[p] - dis[frm[p]]); p = frm[p]; } hp.push(nex); for (int i = 1; i <= k; i++){ if (hp.size() == 0){ flag = false; break; } now = hp.top(); hp.pop(); rd[i].clear(); for (unsigned j = 0; j < now.rd.size(); j++) rd[i].push_back(now.rd[j]); if (mp.find(rd[i]) != mp.end()){ i--; continue; } mp.insert(rd[i]); /* for (unsigned j = 0; j < rd[i].size(); j++) printf("%d%c", rd[i][j], (j == rd[i].size() - 1) ? '\n' : '-'); for (unsigned j = 0; j < rd[i].size(); j++) printf("%d%c", now.d[j], (j == rd[i].size() - 1) ? '\n' : '-'); */ for (unsigned j = now.id; j < now.rd.size() - 1; j++){ memset(tag, false, sizeof(tag)); for (unsigned t = 0; t <= j; t++) tag[now.rd[t]] = true; spfa(T); int u = now.rd[j], v = now.rd[j + 1], mni = 0, mn = inf, np; for (unsigned t = 0; t < eg[u].size(); t++){ int tmpi = eg[u][t], tmp = dis[eg[u][t]] + vg[u][t] + now.d[j]; if (cmp(v, dis[v] + now.d[j + 1], tmpi, tmp) == true && v != tmpi) if (cmp(mni, mn, tmpi, tmp) == false) mni = tmpi, mn = tmp, np = vg[u][t]; } if (mni != 0){ nex.id = j; nex.vote = mn; nex.rd.clear(); nex.d.clear(); for (unsigned k = 0; k <= j; k++) nex.rd.push_back(now.rd[k]), nex.d.push_back(now.d[k]); int tot = nex.d[j], p = mni; nex.rd.push_back(p), nex.d.push_back(tot += np); // printf("%d", nex.d[1]); while (p != T){ nex.rd.push_back(frm[p]); nex.d.push_back(tot += dis[p] - dis[frm[p]]); p = frm[p]; } /* for (unsigned k = 0; k < nex.rd.size(); k++) printf("%d%c", nex.rd[k], (k == nex.rd.size() - 1) ? '\n' : '-'); for (unsigned k = 0; k < nex.rd.size(); k++) printf("%d%c", nex.d[k], (k == nex.d.size() - 1) ? '\n' : '-'); */ hp.push(nex); } // printf("\n"); } // printf("\n"); } if (flag == false) printf("No\n"); else for (unsigned i = 0; i < rd[k].size(); i++) printf("%d%c", rd[k][i], (i == rd[k].size() - 1) ? '\n' : '-'); return 0; }