小记:这题还是要理解了题意就好做了,这题之前做过一次。
题意:从一点送请柬到其它n-1个点,然后再回来的最小路程。
思路:去送的最小路程就是单源最短路径,
而回来,想一下就可以知道,因为图是有向图,所以将图反向之后,那么我到其它n-1个点的最短路径就是他们到我的最短路径了。
因此反向一次在进行一次spfa,将总共两次的spfa的最短距离相加起来就是answer了。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <string> using namespace std; #define mst(a,b) memset(a,b,sizeof(a)) #define REP(a,b,c) for(int a = b; a < c; ++a) #define eps 10e-8 #define DEBUG printf("here\n"); const int MAX_ = 1000010; const int N = 100010; const int INF = 0x7fffffff; int n; struct node{ int u, v; int cap, next; }edge[MAX_*2]; struct point{ int x,y,cap; }p[MAX_]; int H[MAX_*2]; //int V[MAX_*2]; int d[MAX_]; bool vis[MAX_]; int m, cnt, M; void add(int u, int v, int cap) { edge[M].u = u; edge[M].v = v; edge[M].cap = cap; edge[M].next = H[u]; H[u] = M++; } void spfa(int start) { queue<int > q; REP(i, 0, n+1){ vis[i] = 0; d[i] = INF; } vis[start] = 1; d[start] = 0; q.push(start); while(!q.empty()){ int cur = q.front(); q.pop(); vis[cur] = 0; for(int i = H[cur]; i+1; i = edge[i].next){ int v = edge[i].v; int u = edge[i].u; if(d[v] > d[u] + edge[i].cap){ d[v] = d[u] + edge[i].cap; if(!vis[v]){ vis[v] = 1; q.push(v); } } } } return ; } int main(){ int T, ss, tt, v, s, t; char str[10]; scanf("%d", &T); while(T-- && scanf("%d%d", &n, &m)){ //scanf("%d", &m); //mst(g, -1); mst(H, -1); //mst(V, -1); M = 0; REP(i, 0, m){ scanf("%d%d%d", &s, &t, &v); add(s,t,v); p[i].x = s; p[i].y = t; p[i].cap = v; } spfa(1); int sum = 0; REP(i, 1, n+1){ sum += d[i]; } mst(H, -1); //mst(V, -1); M = 0; REP(i, 0, m){ add(p[i].y, p[i].x, p[i].cap); } spfa(1); REP(i, 1, n+1){ sum += d[i]; } /* REP(i, 0, n)REP(j, 0, n){ printf("%.3f ", g[i][j]); if(j == n-1)printf("\n"); }*/ printf("%d\n", sum); } return 0; }