题目大意:
给一张无向联通图,让你用最短路去生成一颗最小生成树,并输出用到的边的编号。
解题思路:
在spfa的时候就可以更新记录用到哪些边,在拥有多种最短路的时候,选择边权小的进行更新记录。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <utility> #include <cmath> #include <queue> #include <set> #include <map> #include <climits> #include <functional> #include <deque> #include <ctime> #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long ll; const int maxn = 300010; const ll inf = 1e16; int cnt, head[maxn]; int pre[maxn], vis[maxn], val[maxn]; ll dis[maxn]; struct edge { int to, w, nxt, id; } e[maxn << 1]; void init() { cnt = 0; memset(head, -1, sizeof(head)); } void add(int u, int v, int w, int id) { e[cnt].to = v; e[cnt].w = w; e[cnt].id = id; e[cnt].nxt = head[u]; head[u] = cnt++; } void spfa(int s) { memset(pre, 0, sizeof(pre)); memset(vis, 0, sizeof(vis)); for(int i = 0; i < maxn; i++) dis[i] = inf; queue <int> que; que.push(s); dis[s] = 0, vis[s] = 1; while (!que.empty()) { int u = que.front(); que.pop(); vis[u] = 0; for (int i = head[u]; ~i; i = e[i].nxt) { int v = e[i].to; //printf("*********%d %d\n", u, v); if (dis[v] > dis[u] + e[i].w) { dis[v] = dis[u] + e[i].w; pre[v] = e[i].id; if (!vis[v]) { vis[v] = 1; que.push(v); } } else if (dis[v] == dis[u] + e[i].w) { if (e[i].w < val[pre[v]]) { pre[v] = e[i].id; if (!vis[v]) { vis[v] = 1; que.push(v); } } } } } } int main() { int n, m; while (~scanf("%d%d", &n, &m)) { init(); for (int i = 1; i <= m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); add(u, v, w, i); add(v, u, w, i); val[i] = w; } //for(int i = 0; i < cnt; i++) //printf("%d %d %d %d\n", e[i].to, e[i].w, e[i].nxt, e[i].id); int s; scanf("%d", &s); spfa(s); ll sum = 0; for (int i = 1; i <= n; i++) if (pre[i]) sum += val[pre[i]]; cout << sum << endl; for (int i = 1; i <= n; i++) if (pre[i]) printf("%d ", pre[i]); printf("\n"); } return 0; }