HDU - 3072 Intelligence System

题意:

  给出一个N个节点的有向图。图中任意两点进行通信的代价为路径上的边权和。如果两个点能互相到达那么代价为0。问从点0开始向其余所有点通信的最小代价和。保证能向所有点通信。

题解:

  求出所有的强连通分量,然后进行缩点操作。最后贪心的找出每个点的最小代价,然后求和。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 5e4+10;
const int inf = 0x3f3f3f3f;
int n, m;
struct node {
    int u, v, w;
}e[maxn<<1];
vector<int> g[maxn];
vector<int> rg[maxn];
vector<int> vs;
bool vis[maxn];
int cmp[maxn], in[maxn];
ll ans;
void add_edge(int u, int v) {
    g[u].push_back(v);
    rg[v].push_back(u);
}
void dfs(int u) {
    vis[u] = true;
    int len = g[u].size();
    for(int i = 0; i < len; i++) {
        int v = g[u][i];
        if(!vis[v]) dfs(v);
    }
    vs.push_back(u);
}
void rdfs(int u, int k) {
    vis[u] = true;
    cmp[u] = k;
    int len = rg[u].size();
    for(int i = 0; i < len; i++) {
        int v = rg[u][i];
        if(!vis[v]) rdfs(v, k);
    }
}
int scc() {
    memset(vis, 0, sizeof(vis));
    vs.clear();
    for(int u = 0; u < n; u++) {
        if(!vis[u]) dfs(u);
    }
    memset(vis, 0, sizeof(vis));
    int k = 0;
    int len = vs.size();
    for(int i = len-1; i >= 0; i--) {
        int v = vs[i];
        if(!vis[v]) rdfs(v, k++);
    }
    return k;
}
int main() {
    while(~scanf("%d%d", &n, &m)) {
        ans = 0;
        for(int i = 0; i < n; i++) {
            g[i].clear();
            rg[i].clear();
        }
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
            add_edge(e[i].u, e[i].v);
        }
        n = scc();
        for(int i = 0; i < n; i++) in[i] = maxn;
        for(int i = 1; i <= m; i++) {
            int u = cmp[e[i].u];
            int v = cmp[e[i].v];
            if(u!=v) in[v] = min(in[v], e[i].w);
        }
        for(int i = 1; i < n; i++) ans += in[i];
        printf("%lld\n", ans);
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/Pneuis/p/8996830.html