2ios
0 2 3算法
2安全
2017 UESTC Training for Graph Theoryspa
UESTC 1639 雲中誰寄錦書來?雁字回時,月滿西樓。
.net
題意:在n個點m條邊的無向圖上,有k個出口從起點出發,每到一個點(包括起點),
該點連出的邊中有d條會被封鎖,求最壞狀況下到達出口的最短路。
Dijkstra拓展
因爲求最壞狀況下的最短路,對於每一個點,顯然最優的前d條邊不能走。
對於邊u->v,必然要先獲得v到出口的最壞狀況下的最短路才能獲得u通過該邊再到出口的最壞狀況下的最短路,code
也就是該邊對於u的價值,因此要從出口往回考慮。
令f[i]表示i到出口的最壞狀況下的最短路,同dijkstra算法同樣,每一個點i能夠分爲f[i]已肯定的和f[i]未肯定的
初始時天然是對於每一個出口x,f[x]=0已肯定。
對於f[v]已肯定的點v,將邊權爲w的邊u->v以f[v]+w爲關鍵字加入小根堆中。
對於每一個點i還要記錄cnt[i]=k,表示到i後,i連出的最優的前k條邊已被封鎖。
每次取出堆頂對應的邊u->v(若f[u]已肯定直接彈出)則該邊爲u連出的(除已被封鎖的邊外)最優的邊
若cnt[u]<d,該邊必然會被封鎖,那麼將cnt[u]加1,彈出堆頂
若cnt[u]=d,那麼能夠肯定f[u]=f[v]+w,再用u更新連向u的邊,彈出堆頂。
重複這一過程直到肯定f[0]的值,該值即爲答案。
時間複雜度 O(nlogn)
空間複雜度 O(n)
blog
#include <iostream> #include <cstdio> #include <queue> #include <vector> #include <cstring> using namespace std; typedef long long LL; typedef pair<int, int> ii; const int MAXN = 1e5 + 8; const int MAXM = 1e6 + 8; const int INF = 2e9 + 8; vector<ii> sons[MAXN]; int dis[MAXN]; int cnt[MAXN]; bool vis[MAXN]; priority_queue<ii, vector<ii>, greater<ii> > pq; //O(nlogn) inline void ex_dijkstra(int n, int d) { memset(vis, false, sizeof vis); int u, v, w, dist, sz, i; while(!pq.empty()){ u = pq.top().second; dist = pq.top().first; pq.pop(); if(vis[u]) continue; else{ if(cnt[u] == d){ dis[u] = dist; vis[u] = true; } else{ cnt[u]++; continue; } } sz = sons[u].size(); for(i = 0; i < sz; i++){ v = sons[u][i].first; w = sons[u][i].second; if(dist + w < dis[v]){ //dis[v] = d + w; pq.push(ii(dist + w, v)); } } } } int main() { #ifdef LOCAL freopen("f.txt", "r", stdin); //freopen("f.out", "w", stdout); int T = 4; while(T--){ #endif // LOCAL ios::sync_with_stdio(false); cin.tie(0); int n, m, k, d, i, u, v, w; //cin >> n; scanf("%d%d%d%d", &n, &m, &k, &d); for(i = 0; i < m; i++){ scanf("%d%d%d", &u, &v, &w); sons[u].push_back(ii(v, (int)w)); sons[v].push_back(ii(u, (int)w)); } for(int i = 0; i <= n; i++){ dis[i] = INF; } for(i = 0; i < k; i++){ scanf("%d", &u); dis[u] = 0; cnt[u] = d; pq.push(ii(0, u)); } ex_dijkstra(n, d); if(dis[0] == INF) puts("-1"); else printf("%d\n", dis[0]); #ifdef LOCAL while(!pq.empty()) pq.pop(); memset(cnt, 0, sizeof cnt); for(i = 0; i <= n; i++) sons[i].clear(); cout << endl; } #endif // LOCAL return 0; }
Thank you!ci
------from ProLights
get