hdu 2121 无固定根的最小树形图

来源:互联网 发布:珍珠控制台模拟软件 编辑:程序博客网 时间:2024/06/03 18:11

题目链接

解析


本题为不是固定根的最小树形图,我们可以虚拟出一根来,然后在把这个根跟每个点相连,相连的点可以设为无穷大,或者设为所有边和大一点,比如为r,然后就可以利用最小树形图进行计算了,计算出的结果减去r,如果比r还大就可以认为通过这个虚拟节点我们连过原图中两个点,即原图是不连通的,我们就可以认为不存在最小树形图。关于输出最小根也挺简单,在找最小入弧时,如果这条弧的起点是虚拟根,那么这条弧的终点就是要求的根。 但是我们根据最小入边的性质,可知,如果没缩点,必然找不到那个根,因为虚拟根连的边都非常大。但是缩点后,找到的必然是最小的那个序号的根。


代码

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <vector>#include <cmath>using namespace std;const int INF=0x3f3f3f3f;const int maxn = 1000+100;typedef long long LL;int deg[maxn];struct node {    int u, v;    LL w;    node ()    {}    node (int _u, int _v, int _w) {        u = _u;        v = _v;        w = _w;    }}edge[maxn*maxn], p[100000+10];LL in[maxn];int vis[maxn], id[maxn], pre[maxn];int pos;LL Directed_MST(int root, int n, int m, node e[]) {    LL ret = 0;    while (1) {        //第一步:找到入边最小边        for (int i=0; i<n; i++)            in[i] = INF;        for (int i=0; i<m; i++) {            int u = e[i].u, v = e[i].v;            if (e[i].w < in[v] && u != v) {                in[v] = e[i].w;                pre[v] = u;                if (u == root)  //找到与源点相连的点就是树形图的根                     pos = i;            }        }        for (int i=0; i<n; i++) { //没有入边,就不会产生最小树形图            if (i == root)                continue;            if (in[i] == INF)                return -1;        }        int cntnode = 0;        memset(id, -1, sizeof(id));        memset(vis, -1, sizeof(vis));        // 第二步:找环        in[root] = 0;        for (int i=0; i<n; i++) {            ret += in[i];            int 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] = cntnode;                id[v] = cntnode++;            }        }        if (cntnode  == 0)            break;        for (int i=0; i<n; i++) {            if (id[i] == -1)                id[i] = cntnode++;        }        //第三步:缩点、重新标记        for (int i=0; i<m; i++) {            int v = e[i].v;            e[i].u = id[e[i].u];            e[i].v = id[e[i].v];            if (e[i].u != e[i].v)                e[i].w -= in[v];        }        n = cntnode;        root = id[root];    }    return ret;}int main() {    int n, m;    while (~scanf("%d%d", &n, &m)) {        memset(deg, 0, sizeof(deg));        memset(pre, 0, sizeof(pre));        memset(id, -1, sizeof(id));        memset(vis, -1, sizeof(vis));        LL sum = 0;        for (int i=0; i<m; i++) {            int u, v;            LL w;            scanf("%d%d%lld", &u, &v, &w);            edge[i] = node(u, v, w);            sum  += w;        }        sum++;        for (int i=m; i<n+m; i++) {            edge[i] = node(n, i-m, sum);        }        LL ans = Directed_MST(n, n+1, n+m, edge);        if (ans == -1 || ans-sum >= sum)            puts("impossible");        else            printf("%lld %d\n", ans-sum, pos-m);        printf("\n");    }    return 0;}
0 0
原创粉丝点击