POJ 1511 Invitation Cards(SPFA)
阿新 • • 發佈:2019-02-16
圖論題目還是做得少,這麼簡單的SPFA都不會做。。看了大神的部落格 http://www.cnblogs.com/scau20110726/archive/2013/05/04/3060299.html
下面是人家的解釋:
最短路
題意: 強調是有向圖 , n個點(1到n標號)m條邊,求出點1到所有點的最短路之和 + 所有點到點1的最短路之和
什麼?求一次最短路,然後 x 2 就是答案? 這樣是錯的,如果是無向圖的話可以這樣,因為可以逆回去走。但是有向圖顯然不是,點1到點a的最短路,和點a到點1的最短路是完全不同的,值不同走過的路徑也不同.要求點1到所有點的最短路,直接執行一次最短路即可。但是要求所有點到點1的最短路,難道要對所有點執行一次最短路嗎?一看點數就可以否定這個想法。可以這樣想,如果點a到點1存在最短路,那麼把這條路徑的邊全部取反,就是點1到點a的最短路了。所有在求了第1次最短路後,將 整個圖的邊取反,再求一次點1到所有點的最短路就行了,可以知道邊都取反後,第一次走過的路徑都不會再走到(都取反了),而從點a可能到點1的可能的邊都成了點1到點a的可能的邊。
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int MAX_N = 1000000 + 100; const int INF = 0x3f3f3f3f; int head[MAX_N]; long long dis[MAX_N]; bool vis[MAX_N]; struct Edge { int v, next; long long w; }; struct E { int u, v; long long w; }; E e[MAX_N]; Edge edge[MAX_N]; int cnt, p, q; void addEdge(int u, int v, long long w) { edge[cnt].v = v; edge[cnt].w = w; edge[cnt].next = head[u]; head[u] = cnt++; } long long SPFA(int src) { int u; memset(vis, 0, sizeof(vis)); memset(dis, INF, sizeof(dis)); dis[src] = 0; vis[src] = true; queue <int> Q; Q.push(src); while(!Q.empty()) { u = Q.front(); Q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = edge[i].next) { if(dis[edge[i].v] > dis[u] + edge[i].w) { dis[edge[i].v] = dis[u] + edge[i].w; if(!vis[edge[i].v]) { Q.push(edge[i].v); vis[edge[i].v]= true; } } } } long long sum = 0; for(int i = 1; i <= p; i++) sum += dis[i]; return sum; } void init() { cnt = 0; memset(head, -1, sizeof(head)); } int main() { int T; scanf("%d", &T); while(T--) { init(); int u, v; long long w; scanf("%d%d", &p, &q); for(int i = 0; i < q; i++) { scanf("%d%d%lld", &u, &v, &w); addEdge(u, v, w); e[i].u = u, e[i].v = v, e[i].w = w; } long long sum = SPFA(1); init(); for(int i = 0; i < q; i++) addEdge(e[i].v, e[i].u, e[i].w); sum += SPFA(1); printf("%lld\n", sum); } return 0; }