码迷,mamicode.com
首页 > 编程语言 > 详细

HDU - 2121 Ice_cream’s world II(朱刘算法+虚根)

时间:2015-08-17 01:03:01      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:给你N个点,M条有向边,问以哪个点为根结点时,能使最小生成树总权值达到最小,输出总权值和根。
如果构不成最小生成树,另外输出

解题思路:这题很巧妙,暴力枚举的话,肯定TLE,所以,这题就需要点技巧了
可以设一个虚根,虚根连接每一个点,权值为所有边的总权值+1。接着,以虚根为根,跑朱刘算法。
跑出结果后,要判断一下,如果最小生成树的总权值比2 * (所有边的总权值+1)还要大,表示虚根至少和两个点相连了,这样最小生成树就是棵假的最小生成树了,因为至少有两个点入度为0了

得到结果时要怎么找到根,可以用边来判断。我们先构造的是m条边,后面又构造了n条边(虚根到每个点),如果某个点的最小入权值为虚根到该点的权值了,那就证明该点就是最小根了。因为只有下标大于等于m的边才是虚根到点的边,所以只要纪录一下下标,最后输出时用下标-m就得到该点了

#include <cstdio>
#include <cstring>

#define M 20010
#define N 1010

struct Edge{
    int from, to, cost;
}E[M];

int n, m, tot;
int Sum;

void AddEdge(int u, int v, int c) {
    E[tot].from = u;
    E[tot].to = v;
    E[tot++].cost = c;
}

void init() {
    tot = 0; Sum = 0;

    int u, v, c;
    for (int i = 0; i < m; i++) {
        scanf("%d%d%d", &u, &v, &c);
        AddEdge(u, v, c);
        Sum += c;
    }

    Sum++;
    for (int i = 0; i < n; i++) {
        AddEdge(n, i, Sum);
    }
}

#define INF 0x3f3f3f3f
int minroot;
int pre[N], vis[N], id[N], in[N];

int Directed_MST(int root) {
    int ans = 0, u, v, tmp;
    while (1) {
        memset(pre, -1, sizeof(pre));
        for (int i = 0; i < n; i++)
            in[i] = INF;
        for (int i = 0; i < tot; i++) {
            u = E[i].from;
            v = E[i].to;
            if (u != v && E[i].cost < in[v]) {
                in[v] = E[i].cost;
                pre[v] = u;
                if (u == root) minroot = i;
            }
        }

        for (int i = 0; i < n; i++) {
            if (i == root)
                continue;
            if (in[i] == INF)
                return -1;
        }
        int cnt = 0;
        memset(vis, -1, sizeof(vis));
        memset(id, -1, sizeof(id));
        in[root] = 0;

        for (int i = 0; i < n; i++) {
            ans += in[i];
            tmp = i;
            while (tmp != root && id[tmp] == -1 && vis[tmp] != i) {
                vis[tmp] = i;
                tmp = pre[tmp];
            }

            if (tmp != root && id[tmp] == -1) {
                u = pre[tmp];
                while (u != tmp) {
                    id[u] = cnt;
                    u = pre[u];
                }
                id[tmp] = cnt++;
            }
        }

        if (cnt == 0)
            break;

        for (int i = 0; i < n; i++)
            if (id[i] == -1)
                id[i] = cnt++;

        for (int i = 0; i < tot; i++) {
            tmp = E[i].to;
            E[i].from  = id[E[i].from];
            E[i].to = id[E[i].to];
            if (E[i].from != E[i].to)
                E[i].cost -= in[tmp];
        }

        n = cnt;
        root = id[root];
    }
    return ans;
}

void solve() {
    n++;
    int ans = Directed_MST(n - 1);

    if (ans == -1 || ans >= 2 * Sum)
        printf("impossible\n");
    else
        printf("%d %d\n", ans - Sum, minroot - m);
    printf("\n");
}

int main() {
    while (scanf("%d%d" ,&n, &m) != EOF) {
        init();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU - 2121 Ice_cream’s world II(朱刘算法+虚根)

标签:

原文地址:http://blog.csdn.net/l123012013048/article/details/47711205

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!