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

链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2121

题目:

Ice_cream’s world II
Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1610    Accepted Submission(s): 354

Problem Description
After awarded lands to ACMers, the queen want to choose a city be her capital. This is an important event in ice_cream world, and it also a very difficult problem, because the world have N cities and M roads, every road was directed. Wiskey is a chief engineer in ice_cream world. The queen asked Wiskey must find a suitable location to establish the capital, beautify the roads which let capital can visit each city and the project’s cost as less as better. If Wiskey can’t fulfill the queen’s require, he will be punishing.

Input
Every case have two integers N and M (N<=1000, M<=10000), the cities numbered 0…N-1, following M lines, each line contain three integers S, T and C, meaning from S to T have a road will cost C.
Output
If no location satisfy the queen’s require, you must be output “impossible”, otherwise, print the minimum cost in this project and suitable city’s number. May be exist many suitable cities, choose the minimum number city. After every case print one blank.
Sample Input
3 1
0 1 1

4 4
0 1 10
0 2 10
1 3 20
2 3 30

Sample Output

impossible 40 0

Author
Wiskey

Source
HDU 2007-10 Programming Contest_WarmUp

Recommend
威士忌

分析与总结:

更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/

不定根最小树形图问题,解决方法是设计一个“虚拟新根点”,这个从这个结点出发可以到达所有点,并且权值是一个很大的值(比所有权值之和大),然后找这个跟结点是否有最小树形图。

而求出真正的跟结点的方法很巧妙, 利用边的位置与虚拟结点的关系。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;  

const int VN = 1005;
const int INF = 0x7fffffff;   

int ans_root;   

template<typename Type>
class Directed_MST{
public:
    void init(int _n){
        n=_n+1; size=0; ans=0;
    }
    void insert(int u, int v, Type _w){
        E[size++].set(u,v,_w);
    }
    Type directed_mst(int root){
        while(true){
            // 1.找最小的前驱边
            for(int i=1; i<n; ++i)
                in[i]=INF;
            for(int i=0; i<size; ++i){
                int u=E[i].u, v=E[i].v;
                if(E[i].w < in[v] && u!=v){
                    pre[v] = u;
                    in[v] = E[i].w;
                    if(u==root){
                        ans_root = i; // 保存的是边的位置i,而不是v
                    }
                }
            }
            for(int i=1; i<n; ++i)if(i!=root){
                if(in[i]==INF) return -1;
            }
            // 2.找环
            int MXid = 1;
            in[root] = 0;
            memset(id, -1, sizeof(id));
            memset(vis, -1, sizeof(id));
            for(int i=1; i<n; ++i){
                ans += 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] = MXid;
                    }
                    id[v] = MXid++;
                }
            }
            if(MXid==1) break; //无环
            for(int i=1; i<n; ++i)
                if(id[i]==-1) id[i] = MXid++;  

            // 3.缩点,重新标记
            for(int i=0; i<size; ++i){
                int u=E[i].u, v=E[i].v;
                E[i].u = id[u];
                E[i].v = id[v];
                if(E[i].u!=E[i].v) E[i].w -= in[v];
            }
            n = MXid;
            root = id[root];
        }
        return ans;
    }  

private:
    struct Edge{
        int u,v;
        Type w;
        void set(int _u,int _v,Type _w){
            u=_u,v=_v,w=_w;
        }
    }E[VN*VN/2];  

    Type ans;         // 所求答案
    Type in[VN];
    int n;            // 结点个数
    int size;         // 边的数量
    int pre[VN];      // 权值最小的前驱边
    int id[VN];
    int vis[VN];     // 是在环中还是在环外
};  

Directed_MST<int>G;  

int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        G.init(n+1);
        int Max = 0;
        for(int i=0; i<m; ++i){
            int a,b;
            int c;
            scanf("%d%d%d",&a,&b,&c);
            if(a==b)continue;
            Max += c;
            G.insert(a+1,b+1,c);
        }
        ++Max;
        // 把n+1设置为虚拟根结点
        for(int i=m; i<m+n; ++i){
            G.insert(n+1, i-m+1, Max);  // 注意虚拟结点n+1与i的关系,当i>m之后,依次从虚拟根结点n+1出发
                                        // 到达1,2,...,n.利用这个关系,当i>m时利用位置就可以确定m+1与其它结点的关系
                                        // 后面要用这个关系输出根结点
        }  

        int ans = G.directed_mst(n+1);  

        if(ans==-1 || ans-Max>=Max)puts("impossible");
        else printf("%d %d\n", ans-Max, ans_root-m);
        puts("");
    }
    return 0;
}

作者:csdn博客 shuangde800

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索and
, acmer
, ice
, World
, Beautify
, The
, |II|IS|S排|排错|错|
最小树形图
hdu2121、ice cream、ice cream cake、icecream12、ice cream可数吗,以便于您获取更多的相关知识。

时间: 2024-12-31 01:37:30

HDU 2121 Ice_cream’s world II:不定根最小树形图的相关文章

HDU 4009 Transfer water:最小树形图

链接: http://acm.hdu.edu.cn/showproblem.php?pid=4009 题目: Transfer water Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2508    Accepted Submission(s): 934 Problem Description XiaoA lives in a vi

poj 3164 Command Network:最小树形图模板题

链接: http://poj.org/problem?id=3164 题目: Command Network Time Limit: 1000MS     Memory Limit: 131072K Total Submissions: 8922     Accepted: 2609 Description After a long lasting war on words, a war on arms finally breaks out between littleken's and Knu

hdu 3746 Cyclic Nacklace

点击打开链接hdu 3746 思路:kmp+字符串的最小循环节问题 分析: 1 题目要求的是给定一个字符串,问我们还需要添加几个字符可以构成一个由n个循环节组成的字符串. 2 可知我们应该先求出字符串的最小循环节的长度:假设字符串的长度为len,那么最小的循环节就是cir = len-next[len] ; 如果有len%cir == 0,那么这个字符串就是已经是完美的字符串,不用添加任何字符:如果不是完美的那么需要添加的字符数就是cir - (len-(len/cir)*cir)),相当与需要

POJ题目分类

初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      (4)递推.      (5)构造法.(poj3295)      (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法:      (1)图的深度优先遍历和广度优先遍历.      (2)最短路径算法(dijkstra,bellman-ford

poj分类

初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      (4)递推.      (5)构造法.(poj3295)      (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法:      (1)图的深度优先遍历和广度优先遍历.      (2)最短路径算法(dijkstra,bellman-ford

ACM练级

一般要做到50行以内的程序不用调试.100行以内的二分钟内调试成功.acm主要是考算法的 ,主要时间是花在思考算法上,不是花在写程序与debug上.  下面给个计划你练练: 第一阶段: 练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码, 因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打 出来.  1.最短路(Floyd.Dijstra,BellmanFord)  2.最小生成树(先写个prim,kruscal要用并查集,不好写)  3.大数(

poj系统训练计划

转载:http://www.cnblogs.com/silveryelf/archive/2011/10/29/2228681.html 初级: 基本算法: 枚举:1753    2965 贪心:1328    2109    2586 构造:3295 模拟:1068    2632    1573    2993    2996 图: 最短路径:1860    3259    1062    2253    1125    2240 最小生成树:1789    2485    1258    

TreeSplitter---树形分词算法

注:思路不是原创,首先感谢思维的突发奇想者 一. 说明: 目前分词的算法很多,现成的分词组件也不少,但很难找到一个我自己需要的,我只要一个分词功能,一个能理所当然完成分词工作的东西,理所当然是指词库里有什么词就能分出什么词.一些智能分词的目标是毋庸置疑的,难度也是随着智能的程度而增加,不是你我(只少不是我)随随便便走在大街上就能突发奇想出来的.一些成熟的分词方法是基于词库的,本着DRY原则以至于DRO(Don't repeat others),君要了解请看这里或直接Google.其中的不足,思路

算法:uva 10859 Placing Lampposts (树形dp)

题目大意 给你一个n个点m条边的无向无环图,在尽量少的节点上放灯,使得所有边都被照亮. 每盏灯将照亮以它为一个端点的所有边. 在灯的总数最小的前提下,被两盏灯同时被照亮的边数应该 尽量大. 思路 这是LRJ<训练指南>上的例题. 这题教会了我一个很有用的技巧:有 两个所求的值要优化,比如让a尽量小,b也尽量小 那么可以转化为让 M*a+b尽量小,其中M应该是 一个比"a的最大值和b的最小值之差"还要大的数 最终的答案为ans/M, ans%M 回到这题,要 求放的灯总数最小