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

题目大意:给你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;
}

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

时间: 2024-08-09 19:53:35

HDU - 2121 Ice_cream’s world II(朱刘算法+虚根)的相关文章

hdu2121 - Ice_cream’s world II(朱刘算法,不固定根)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2121 题目意思大概是要你在一些城市中选一个做首都 , 要求首都都能到其他城市 , 道路花费要最少 , 且道路都是单向的 , 这个时候就要用到最小树形图算法了 , 而且是不固定根. 不定根就是加一个虚根(原本不存在的点) , 可以让这个虚根到每个点的距离大于原本所有点连接的道路花费之和sum , 然后计算出的结果减去sum,如果比sum还大就可以认为通过这个虚拟节点我们连过原图中两个点,即原图是不连通

hdu 2121 Ice_cream’s world II

真的是一下午都砸在这题上了 不对 是从上午10点到现在都砸掉了 啊啊啊啊啊啊啊啊我有毒吧!!!!!!! 我真的是不想再看到这道题了 卡了电脑3遍啊啊啊啊啊为什么!!!!! 生无可恋脸 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<string> 7 #def

HDU 2121 Ice_cream’s world II (不定根最小树形图)

题目地址:HDU 2121 这题没有给定根.最容易想到的当然是暴力,枚举所有的根,但是TLE是显然的..为了处理不定根的情况,可以虚拟一个根,然后用这个根去跟所有的点连边,权值为其他所有权值的和+1,目的是防止成为最小树形图的一条边.然后跑出最小树形图后,那么这个虚拟根肯定跟一个实际根相连,这时候根就找到了,然后再在最终的总花费中减去虚拟的那条边的权值就可以了. 代码如下: #include <iostream> #include <string.h> #include <m

HDU 2121 Ice_cream’s world II(无定根最小树形图)

Ice_cream’s world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3115    Accepted Submission(s): 737 Problem Description After awarded lands to ACMers, the queen want to choose a city be her

HDU 2121 Ice_cream’s world II 最小树形图

这个题就是需要求整个有向带权图的最小树形图,没有指定根,那就需要加一个虚根 这个虚根到每个点的权值是总权值+1,然后就可以求了,如果求出来的权值大于等于二倍的总权值,就无解 有解的情况,还需要输出最根,多解的情况,肯定是某个环上所有的点为根都可以(比如所有的点构成一个环), 这样加边的时候虚边的时候按照点的标号从小到大编,这样第一个以虚根为前驱的点也是最小的点就可以标记(标记一下) #include <iostream> #include <algorithm> #include

HDOJ 2121 Ice_cream’s world II 最小树形图无根树

朱刘算法 最小树形图无根树: 建立一个虚拟的根节点,向所有节点连边,权值为其他所有边的权值和+1 在求最小树形图的时候,记录和虚拟的根相连的是哪个节点 在这题中,边是从小往大加的所以直接记录的是相连的是第几号边.... Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3442    Accept

HDUOJ--2121--Ice_cream’s world II【朱刘算法】不定根最小树形图

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2121 题意:n个顶点,m条边,求从某一点起建立有向图最小生成树并且花费最小,输出最小花费和根节点下标. 思路:这道题根是不确定的,我们可以先假设一个根,从这个根出发到任何一点的距离(sum)都比原图总权值还大,这样保证了虚拟的边不会是最小入边,也为之后判断是否生成了最小树形图提供方便,从这个点开始建立最小树形图,最后生成出一个结果,很显然虚拟的根只有一条出边,并且出边连接的点就是真实的根. 最后得到的最

hdoj 2121 Ice_cream’s world II 【没有最低树的根节点】

称号:pid=2121" target="_blank">hdoj 2121 Ice_cream's world II 题意:题目是一道躶题,给n个点,m条边的有向图.然后找一个点.到全部点的距离和最小.找出这个点并输入距离. 分析:非常明显是求一个最小树形图,可是没有说根节点.要找跟节点,我们能够虚拟一个节 点 x .x 到全部节点连边距离为前面全部距离和+1为 dis . 然后从x 节点求一次最小树形图为ans,则ans - dis 就是最小树形图的距离. 假设图不

hdoj 2121 Ice_cream’s world II 【无根节点最小树形图】

题目:hdoj 2121 Ice_cream's world II 题意:题目是一道躶题,给n个点,m条边的有向图,然后找一个点,到所有点的距离和最小,找出这个点并输入距离. 分析:很明显是求一个最小树形图,但是没有说根节点,要找跟节点,我们可以虚拟一个节 点 x ,x 到所有节点连边距离为前面所有距离和+1为 dis . 然后从x 节点求一次最小树形图为ans,则ans - dis 就是最小树形图的距离. 如果图不连通,或者ans>=2*dis 说明不存在,都则与 x 点出发的边就是结果点 A