hdu2121+不定根最小树形图

来源:互联网 发布:手机淘宝怎样实人认证 编辑:程序博客网 时间:2024/06/05 14:34

算和定根最小树形图相同。

我们只需:设一个权值sumw=所有边之和+1,类似于网络流,向图中加入一个超级源点,把这个点作为虚根。虚根到其他所有点之间连上一条边,边权值为sumw.

求出的值减去sumw即为最小树形图的权值。

当然,返回-1则无解。此外,当求出的值>=2*sumw,也是无解的。

#include<cstdio>#include<cstring>using namespace std;struct node{    int u,v;    long long int w;}edge[22000];int n,m,pre[1100],minroot,sume;long long int in[1100],mmax;long long int solve(int root){    int mark[1100],vis[1100],i;    long long int ans=0;    while(true)    {       for(i=0;i<n;i++)        in[i]=mmax;       for(i=0;i<sume;i++)       {           int u1=edge[i].u;           int v1=edge[i].v;           if(edge[i].w<in[v1]&&u1!=v1)           {               in[v1]=edge[i].w;               pre[v1]=u1;               if(u1==root) minroot=i;           }       }       for(i=0;i<n;i++)       {           if(i==root) continue;           if(in[i]==mmax) return -1;       }       int cnt=0;       memset(vis,-1,sizeof(vis));       memset(mark,-1,sizeof(mark));       in[root]=0;       for(i=0;i<n;i++)       {           ans+=in[i];           int v=i;           while(v!=root&&vis[v]!=i&&mark[v]==-1)           {               vis[v]=i;               v=pre[v];           }           if(v!=root&&mark[v]==-1)           {               int u;               for(u=pre[v];u!=v;u=pre[u])               {                   mark[u]=cnt;               }               mark[v]=cnt++;           }       }       if(cnt==0) break;       for(i=0;i<n;i++)       {           if(mark[i]==-1)            mark[i]=cnt++;       }       for(i=0;i<sume;i++)       {           int u2=edge[i].u;           int v2=edge[i].v;           edge[i].u=mark[u2];           edge[i].v=mark[v2];           if(mark[u2]!=mark[v2])            edge[i].w-=in[v2];       }       n=cnt;       root=mark[root];    }    return ans;}int main(){    int i;    long long int sum;    mmax=999999999999999;    while(scanf("%d%d",&n,&m)!=EOF)    {        sum=0;        for(i=0;i<m;i++)        {            scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);            sum+=edge[i].w;        }        for(i=m;i<n+m;i++)        {            edge[i].u=n;            edge[i].v=i-m;            edge[i].w=sum+1;        }        sume=n+m;        n++;        long long int aans=solve(n-1);        if(aans==-1||aans>=(2*sum+2)) printf("impossible\n");        else        printf("%I64d %d\n",aans-sum-1,minroot-m);        printf("\n");    }    return 0;}


0 0
原创粉丝点击