http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1443
给定一幅无向带权连通图G = (V, E) (这里V是点集,E是边集)。从点u开始的最短路径树是这样一幅图G1 = (V, E1),其中E1是E的子集,并且在G1中,u到所有其它点的最短路径与他在G中是一样的。
现在给定一幅无向带权连通图G和一个点u。你的任务是找出从u开始的最短路径树,并且这个树中所有边的权值之和要最小。
最短路加最小生成树合在一起就ok 了!
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#define LL long long
#define MAXN 300005
using namespace std;
int n, m;
LL dist[MAXN];
int inQueue[MAXN], root[MAXN];
int in[MAXN];
vector <pair< int, LL> > G[MAXN];
queue <int> Q;
struct Edge
{
int u, v;
LL cost;
Edge(int U = -1, int V = -1, LL C = -1)
{
u = U;
v = V;
cost = C;
}
bool operator < (const Edge& x) const
{
return cost < x.cost;
}
};
vector <Edge> edge;
int findRoot(int x)
{
if(x == root[x]) return x;
else
return root[x] = findRoot(root[x]);
}
void unite(int x, int y)
{
x = findRoot(x);
y = findRoot(y);
if(x == y) return;
root[x] = root[y];
}
void spfa(int star)
{
memset(dist, -1, sizeof(dist));
memset(inQueue, 0, sizeof(inQueue));
while(!Q.empty()) Q.pop();
dist[star] = 0;
inQueue[star] = 1;
Q.push(star);
while(!Q.empty())
{
int now = Q.front();
Q.pop();
inQueue[now] = 0;
int siz = G[now].size();
for(int i = 0; i < siz; i++)
{
int v = G[now][i].first;
LL cost = G[now][i].second;
if(dist[v] == -1 || dist[v] > dist[now] + cost)
{
dist[v] = dist[now] + cost;
if(!inQueue[v])
{
inQueue[v] = 1;
Q.push(v);
}
}
}
}
}
LL Kruskal()
{
LL res = 0;
memset(in, 0, sizeof(in));
sort(edge.begin(), edge.end());
int siz = edge.size();
for(int i = 0; i < siz; i++)
{
int u = edge[i].u, v = edge[i].v;
LL cost = edge[i].cost;
if(in[v] || findRoot(u) == findRoot(v)) continue;
in[v] = 1;
unite(u, v);
res += cost;
}
return res;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
for(int i = 0; i <= n; i++)
{
G[i].clear();
root[i] = i;
}
for(int i = 0; i < m; i++)
{
int u, v, cost;
scanf("%d%d%d", &u, &v, &cost);
G[u].push_back(make_pair(v, (LL)cost));
G[v].push_back(make_pair(u, (LL)cost));
}
int star;
scanf("%d", &star);
spfa(star);
edge.clear();
for(int i = 1; i <= n; i++)
{
int siz = G[i].size();
for(int j = 0; j < siz; j++)
{
int v = G[i][j].first;
LL cost = G[i][j].second;
if(dist[v] == dist[i] + cost)
{
edge.push_back(Edge(i, v, cost));
}
}
}
printf("%lld\n", Kruskal());
}
return 0;
}