uva 11183 Teen Girl Squad (最小树形图)

uva 11183 Teen Girl Squad

题目大意:你有一个好消息要告诉你的n-1个朋友,不过你们不在同一个地方,因此只能靠打电话。给出m个三元组(u, v, w)表示u打电话给v要花w的钱(v不能给u打电话),你的任务是用最少的总费用把这个好消息通知到所有人。
解题思路:有向的最小生成树。最小树形图,用朱刘算法。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
const int N = 1005;
const int M = 40005;
const int INF = 0x3f3f3f3f;

typedef long long ll;
int n, m;
int Gra[N][N], cnt;
int pre[N], id[N], vis[N], in[N];
struct Edge{
    int u, v, d;    
}edges[M];

void init() {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            Gra[i][j] = INF;    
        }   
    }
}

void input() {
    int u, v, d;
    for (int i = 0; i < m; i++) {
        scanf("%d %d %d", &u, &v, &d);  
        if (u == v) continue;
        Gra[u][v] = min(Gra[u][v], d);
    }
    cnt = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (Gra[i][j] == INF) continue; 
            edges[cnt].u = i;   
            edges[cnt].v = j;
            edges[cnt++].d = Gra[i][j];
        }
    }
}

int ZL(int root) {
    int ans = 0, u, v;
    while (1) {
        for (int i = 0; i < n; i++) in[i] = INF;
        for (int i = 0; i < cnt; i++) {
            if (edges[i].u == edges[i].v) continue;
            if (edges[i].d < in[edges[i].v]) {
                pre[edges[i].v] = edges[i].u;
                in[edges[i].v] = edges[i].d;
            }   
        }
        for (int i = 0; i < n; i++) {
            if (i != root && in[i] == INF) return -1;
        }
        int tn = 0;
        memset(id, -1, sizeof(id));
        memset(vis, -1, sizeof(vis));
        in[root] = 0;
        for (int i = 0; i < n; i++) {
            ans += in[i];   
            v = i;
            while (vis[v] != i && id[v] == -1 && v != root) {
                vis[v] = i; 
                v = pre[v];
            }
            if (v != root && id[v] == -1) {
                for (int u = pre[v]; u != v; u = pre[u]) {
                    id[u] = tn;
                }   
                id[v] = tn++;
            }
        }
        if (tn == 0) break;
        for (int i =  0; i < n; i++) {
            if (id[i] == -1) id[i] = tn++;
        }
        for (int i = 0; i < cnt; ) {
            v = edges[i].v;
            edges[i].u = id[edges[i].u];
            edges[i].v = id[edges[i].v];
            if (edges[i].u != edges[i].v) edges[i++].d -= in[v];
            else swap(edges[i], edges[--cnt]);
        }
        n = tn;
        root = id[root];
    }
    return ans;
}

void solve() {
    int ans = ZL(0);
    if (ans == -1) printf("Possums!\n");
    else printf("%d\n", ans);
}

int main() {
    int T, Case = 1;
    scanf("%d", &T);
    while (T--) {
        printf("Case #%d: ", Case++);
        scanf("%d %d", &n, &m); 
        init();
        input();
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值