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

来源:互联网 发布:node 模块开发 编辑:程序博客网 时间:2024/05/18 00:54
Ice_cream’s world IITime Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4738    Accepted Submission(s): 1164Problem DescriptionAfter 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.InputEvery 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.OutputIf 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 Input3 10 1 14 40 1 100 2 101 3 202 3 30Sample Outputimpossible40 0AuthorWiskeySourceHDU 2007-10 Programming Contest_WarmUpRecommend威士忌   |   We have carefully selected several similar problems for you:  2120 2122 1222 4009 2064 

好难….费了好长时间才AC
难点有2:
①:不定根 朱刘算法 穷举每个点为根 显然会超时
解法很巧妙 新建一个虚拟根 连接到其他所有点 边权Wr足够大
这样跑一遍朱刘 如果mdst>=2Wr 就表明mdst里虚拟根有2条出边 不存在mdst
如果mdst<2Wr mdst-Wr就是最小树形图的值
②:求根 刚开始学mdst的模板是邻接矩阵O(n^3) 显然超时 后来找了O(VE)版本的模板 发现…这个板子会修改点的标号…这就很尴尬了….
解法是 记录下虚拟根的出边的下标 添加虚拟边时 从{虚拟根->0},{虚拟根->1},…,{虚拟根->n-1} 所以第一条出边{u,v}的v就是最小的根


#include<iostream>#include<stdlib.h>#include<stdio.h>#include<string>#include<vector>#include<deque>#include<queue>#include<algorithm>#include<set>#include<map>#include<stack>#include<time.h>#include<math.h>#include<list>#include<cstring>#include<fstream>//#include<memory.h>using namespace std;#define ll long long#define ull unsigned long long#define pii pair<int,int>//#define INF 1000000007#define pll pair<ll,ll>#define pid pair<int,double>const int MAXN = 1010;const int MAXM = 10010+MAXN;const ll INF=1e18+1;struct Edge{    int u,v,cost;};Edge edge[MAXM];int pre[MAXN],id[MAXN],visit[MAXN];ll in[MAXN];int rootIndex;//根节点连接到其他点的边的下标 当点为0-n-1 虚拟的根节点为n时 rootIndex-m就是真正的根节点下标ll zhuliu(int root,int n,int m,Edge edge[])//PS:会改变edge[]{    ll res = 0;    int u,v;    while(1)    {        for(int i = 0;i < n;i++)            in[i] = INF;//入边边权为inf        for(int i = 0;i < m;i++)            if(edge[i].u != edge[i].v && edge[i].cost < in[edge[i].v])            {//找出所有点的最小入边集E0                pre[edge[i].v] = edge[i].u;                in[edge[i].v] = edge[i].cost;                if(edge[i].u==root)//因为从虚拟根连出的边 依次从0-n-1添加进去 第一条出边连接的点 原标号最小                    rootIndex=i;            }        for(int i = 0;i < n;i++)            if(i != root && in[i] == INF)                return -1;//有除根节点外的点 无入边 不存在最小树形图        int tn = 0;        memset(id,-1,sizeof(id));        memset(visit,-1,sizeof(visit));        in[root] = 0;        for(int i = 0;i < n;i++)//找环        {            res += in[i];            v = i;            while( visit[v] != i && id[v] == -1 && v != root)//对点进行标记 走到的点如果已经被标记(不是根) 存在环            {                visit[v] = i;                v = pre[v];            }            if( v != root && id[v] == -1 )//存在环            {                for(int u = pre[v]; u != v ;u = pre[u])//将环中的点全部标为tn号点                    id[u] = tn;                id[v] = tn++;            }        }        if(tn == 0)break;//没有有向环        for(int i = 0;i < n;i++)//为未被标号的点标号            if(id[i] == -1)                id[i] = tn++;        for(int i = 0;i < m;++i)//更新边        {            v = edge[i].v;            edge[i].u = id[edge[i].u];            edge[i].v = id[edge[i].v];            if(edge[i].u != edge[i].v)                edge[i].cost -= in[v];//E0已经被添加进res了 减去入边权        }        n = tn;        root = id[root];    }    return res;}int main(){    //freopen("/home/lu/文档/r.txt","r",stdin);    //freopen("/home/lu/文档/w.txt","w",stdout);    int n,m,u,v,c;    while(~scanf("%d%d",&n,&m)){        ll sumc=0;        for(int i=0;i<m;++i){            scanf("%d%d%d",&u,&v,&c);            edge[i]={u,v,c};            sumc+=c;        }        ++sumc;//虚拟的根节点连接到其他边的权值=所有边权和+1        for(int i=0;i<n;++i)            edge[i+m]={n,i,sumc};        ll ans=zhuliu(n,n+1,m+n,edge);        if(ans>=sumc*2||ans==-1){            puts("impossible");        }        else{            printf("%lld %lld\n",ans-sumc,rootIndex-m);        }        putchar('\n');    }    return 0;}
0 0
原创粉丝点击