题目链接:Paths and Trees
【题意】给出一张无向连通图,求点u到所有点最短路不变的情况下的最小生成树;
【分析】一开始往最小树形图想,可是会超时,果断不会了。其实在连通图上的一点出发到所有点的最短路就是一颗生成树(看来还没完全理解最短路),然而只要在求最短路的时候让每条边的权值尽量小即可。用了spfa做。
【AC CODE】451ms
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> //#include <unordered_set> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int MAXN = 300000+10, MAXM = 300000*2+10; int head[MAXN], tol, nxt[MAXM], to[MAXM], c[MAXM]; inline void add_edge(int u, int v, int cost) { nxt[tol] = head[u], to[tol] = v, c[tol] = cost; head[u] = tol++; } bool inq[MAXN]; LL dis[MAXN]; int fre[MAXN]; void spfa(int st) { queue<int> q; q.push(st); inq[st] = true; clc(dis,0x3f); dis[st] = 0; while(!q.empty()) { int u = q.front();q.pop(); inq[u] = false; for(int i = head[u]; ~i; i= nxt[i]) { int v = to[i]; if(dis[v] > dis[u]+c[i]) { dis[v] = dis[u]+c[i]; fre[v] = i; if(!inq[v]) { q.push(v); inq[v] = true; } } else if(dis[v] == dis[u]+c[i] && c[i] < c[fre[v]]) { fre[v] = i; /*if(!inq[v]) { q.push(v); inq[v] = true; }*/ } } } } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif int n,m; scanf("%d %d%*c", &n,&m); clc(head,-1); tol = 0; rep(i,0,m) { int u,v,cost; scanf("%d %d %d%*c", &u, &v, &cost); add_edge(u,v,cost); add_edge(v,u,cost); } int st; scanf("%d\n", &st); spfa(st); LL sum = 0; repe(i,1,n) { if(i != st) sum += c[fre[i]]; } printf("%I64d\n", sum); repe(i,1,n) { if(i == st) continue; printf("%d ", fre[i]/2+1); } putchar('\n'); return 0; }