51nod 1443 路径和树

26 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值