hdu2121+不定根最小树形图

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

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

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

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

 

  1 #include<cstdio>
  2 #include<cstring>
  3 using namespace std;
  4 struct node
  5 {
  6     int u,v;
  7     long long int w;
  8 }edge[22000];
  9 int n,m,pre[1100],minroot,sume;
 10 long long int in[1100],mmax;
 11 long long int solve(int root)
 12 {
 13     int mark[1100],vis[1100],i;
 14     long long int ans=0;
 15     while(true)
 16     {
 17        for(i=0;i<n;i++)
 18         in[i]=mmax;
 19        for(i=0;i<sume;i++)
 20        {
 21            int u1=edge[i].u;
 22            int v1=edge[i].v;
 23            if(edge[i].w<in[v1]&&u1!=v1)
 24            {
 25                in[v1]=edge[i].w;
 26                pre[v1]=u1;
 27                if(u1==root) minroot=i;
 28            }
 29        }
 30        for(i=0;i<n;i++)
 31        {
 32            if(i==root) continue;
 33            if(in[i]==mmax) return -1;
 34        }
 35        int cnt=0;
 36        memset(vis,-1,sizeof(vis));
 37        memset(mark,-1,sizeof(mark));
 38        in[root]=0;
 39        for(i=0;i<n;i++)
 40        {
 41            ans+=in[i];
 42            int v=i;
 43            while(v!=root&&vis[v]!=i&&mark[v]==-1)
 44            {
 45                vis[v]=i;
 46                v=pre[v];
 47            }
 48            if(v!=root&&mark[v]==-1)
 49            {
 50                int u;
 51                for(u=pre[v];u!=v;u=pre[u])
 52                {
 53                    mark[u]=cnt;
 54                }
 55                mark[v]=cnt++;
 56            }
 57        }
 58        if(cnt==0) break;
 59        for(i=0;i<n;i++)
 60        {
 61            if(mark[i]==-1)
 62             mark[i]=cnt++;
 63        }
 64        for(i=0;i<sume;i++)
 65        {
 66            int u2=edge[i].u;
 67            int v2=edge[i].v;
 68            edge[i].u=mark[u2];
 69            edge[i].v=mark[v2];
 70            if(mark[u2]!=mark[v2])
 71             edge[i].w-=in[v2];
 72        }
 73        n=cnt;
 74        root=mark[root];
 75     }
 76     return ans;
 77 }
 78 int main()
 79 {
 80     int i;
 81     long long int sum;
 82     mmax=999999999999999;
 83     while(scanf("%d%d",&n,&m)!=EOF)
 84     {
 85         sum=0;
 86         for(i=0;i<m;i++)
 87         {
 88             scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
 89             sum+=edge[i].w;
 90         }
 91         for(i=m;i<n+m;i++)
 92         {
 93             edge[i].u=n;
 94             edge[i].v=i-m;
 95             edge[i].w=sum+1;
 96         }
 97         sume=n+m;
 98         n++;
 99         long long int aans=solve(n-1);
100         if(aans==-1||aans>=(2*sum+2)) printf("impossible\n");
101         else
102         printf("%I64d %d\n",aans-sum-1,minroot-m);
103         printf("\n");
104     }
105     return 0;
106 }

 

posted @ 2016-04-02 22:05  2014551532  阅读(239)  评论(0编辑  收藏  举报