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

来源:互联网 发布:大司马淘宝店网址 编辑:程序博客网 时间:2024/06/01 09:25

Ice_cream’s world II

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1958    Accepted Submission(s): 453


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 10 1 14 40 1 100 2 101 3 202 3 30
 

Sample Output
impossible40 0
题意:给出一个有向图,求这个图的最小树形图,它的根是不定的,要求出最小树形图的权值和根的标号,若根的标号不唯一,输出最小的标号。
思路:这题要求不定根的最小树形图。做法是:虚拟出一个虚根,将虚根连到原图中的各点,每条虚边的权值相等且比原图中所有边的权值的总和还要大(将它设为原图中所有边的权值总和+1即可),最后将最小树形图的权值减去虚边的权值即为最终结果。在找最小入边时,先选择原图上的边,再选择虚边,若能加入一条虚边进最小树形图,那么与虚边相连的必定就是最后最小树形图的根。而且只能加入一条虚边,如果加入了两条虚边,则说明原图中孤立的点不止一个,这种情况不存在最小树形图。
AC代码:
#include <cstring>#include <string>#include <cstdio>#include <algorithm>#include <queue>#include <cmath>#include <vector>#include <cstdlib>#include <iostream>#define max2(a,b) ((a) > (b) ? (a) : (b))#define min2(a,b) ((a) < (b) ? (a) : (b))using namespace std;const double INF=10000000;const int N=1005;struct node{    int u,v;    int w;}edge[12000];int in[N];int pre[N],hash[N],vis[N];int n,cntedge,minroot;void add(int u,int v,int w){    edge[cntedge].u=u;    edge[cntedge].v=v;    edge[cntedge].w=w;    cntedge++;}int Directed_MST(int root){    int sum=0;    while(1)    {        for(int i=0; i<=n; i++)            in[i]=INF;        for(int i=0; i<cntedge; i++) //找最小入边        {            int u=edge[i].u;            int v=edge[i].v;            if(edge[i].w<in[v]&&u!=v)  //重构的新图可能存在自环            {                if(u==root) minroot=i;    //若虚边比原来的入边小,则对应的点在最小生成图中与虚根相连                pre[v]=u;                in[v]=edge[i].w;            }        }        for(int i=0; i<=n; i++) //判断是否存在最小树形图        {            if(i==root) continue;            if(in[i]==INF) return -1;        }        int cntnode=0;        memset(hash,-1,sizeof(hash));        memset(vis,-1,sizeof(vis));        in[root]=0;        for(int i=0; i<=n; i++)  //检查是否存在环        {            sum+=in[i];            int v=i;            while(vis[v]!=i&&hash[v]==-1&&v!=root)            {                vis[v]=i;                v=pre[v];            }            if(v!=root&&hash[v]==-1)      //若存在环,将环缩点            {                for(int u=pre[v]; u!=v; u=pre[u])                    hash[u]=cntnode;                hash[v]=cntnode++;            }        }        if(cntnode==0) break;   //若不存在环,算法终止        for(int i=0; i<=n; i++) //构新图            if(hash[i]==-1)                hash[i]=cntnode++;        for(int i=0; i<cntedge; i++)        {            int v=edge[i].v;            edge[i].u=hash[edge[i].u];            edge[i].v=hash[edge[i].v];            if(edge[i].u!=edge[i].v)                edge[i].w-=in[v];        }        n=cntnode-1;        root=hash[root];    }    return sum;}int main(){    int a,b,m,c;    while(scanf("%d%d",&n,&m)!=EOF)    {        cntedge=0;        int sum=0;        for(int i=0; i<m; i++)        {            scanf("%d%d%d",&a,&b,&c);            if(a==b) continue;      //不能存在自环            sum+=c;            add(a,b,c);        }        m=cntedge;        sum++;               //设虚边的权值为所有边权值和+1        for(int i=0;i<n;i++)        add(n,i,sum);        //将虚边与各个点相连        int ans=Directed_MST(n);        if(ans==-1||ans>=2*sum)    //ans>=2*sum表示加入了两条虚边,表明原图不连通,不存在生成树        printf("impossible\n\n");        else        printf("%d %d\n\n",ans-sum,minroot-m);  //虚边的标号-原图边的总数即为根的标号。    }    return 0;}