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 }
时间: 2024-08-06 23:39:04

hdu2121+不定根最小树形图的相关文章

HDUOJ--2121--Ice_cream’s world II【朱刘算法】不定根最小树形图

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2121 题意:n个顶点,m条边,求从某一点起建立有向图最小生成树并且花费最小,输出最小花费和根节点下标. 思路:这道题根是不确定的,我们可以先假设一个根,从这个根出发到任何一点的距离(sum)都比原图总权值还大,这样保证了虚拟的边不会是最小入边,也为之后判断是否生成了最小树形图提供方便,从这个点开始建立最小树形图,最后生成出一个结果,很显然虚拟的根只有一条出边,并且出边连接的点就是真实的根. 最后得到的最

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

题目地址:HDU 2121 这题没有给定根.最容易想到的当然是暴力,枚举所有的根,但是TLE是显然的..为了处理不定根的情况,可以虚拟一个根,然后用这个根去跟所有的点连边,权值为其他所有权值的和+1,目的是防止成为最小树形图的一条边.然后跑出最小树形图后,那么这个虚拟根肯定跟一个实际根相连,这时候根就找到了,然后再在最终的总花费中减去虚拟的那条边的权值就可以了. 代码如下: #include <iostream> #include <string.h> #include <m

HDU2121 Ice_cream’s world II 【最小树形图】+【不定根】

Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2744    Accepted Submission(s): 630 Problem Description After awarded lands to ACMers, the queen want to choose a city be he

HDU2121 Ice_cream’s world II【最小树形图】【不定根】

Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3005    Accepted Submission(s): 704 Problem Description After awarded lands to ACMers, the queen want to choose a city be he

hdu2121 最小树形图的虚根

/* 最小树形图的第二题,终于有了一些理解 具体看注释 */ /* 无定根的最小树形图 建立虚root 每次只找最短的那条入边 最小树形图理解: 第一步:寻找最短弧集E:扫一遍所有的边,找到每个点权值最小的入边,这一步会产生环 第二步:对每个点 i 找环:通过第一步记录的前驱找环,如果找到了原点或退到了另一个环,点i找环失败 第三步:缩点,缩点就是染色,把每个环内的点染上同一种颜色,每个环内点打上同一个id 第四步:更新一次边集:如果一条边连接两个不同颜色的点,就该边这条边的权值 重复以上四步.

hdu2121 Ice_cream’s world II 最小树形图(难)

这题比HDU4009要难一些.做了4009,大概知道了最小树形图的解法.拿到这题,最直接的想法是暴力.n个点试过去,每个都拿来做一次根.最后WA了,估计是超时了.(很多题都是TLE说WA,不断修改代码也看不出来错哪了). 网上的正解是添加一个虚拟根(树根),使得它与n个点都有边相连.HDU4009题这样得到的边有实际的意义,好理解.这题这样得到的边不好理解,并且边权应该是多少也有讲究.别人的解题报告中是把这些边的权值设为原本所有边的权值之和加1.这样做的目的,是为了完全把这些边与原本的边区分开.

HDU4009 Transfer water【最小树形图】【不定根】

Transfer water Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 3943    Accepted Submission(s): 1415 Problem Description XiaoA lives in a village. Last year flood rained the village. So they dec

树的问题小结(最小生成树、次小生成树、最小树形图、LCA、最小支配集、最小点覆盖、最大独立集)

树的定义:连通无回路的无向图是一棵树. 有关树的问题: 1.最小生成树. 2.次小生成树. 3.有向图的最小树形图. 4.LCA(树上两点的最近公共祖先). 5.树的最小支配集.最小点覆盖.最大独立集. 一.最小生成树 解决的问题是:求无向图中边权值之和最小的生成树. 算法有Kruskal和Prim. Kruskal使用前向星和并查集实现,可以存储重边(平行边),时间复杂度是O(m log m  +  m),m是边的数量. Prim使用邻接矩阵建图,不可以存储重边(平行边),如果出现重边,存储的

bzoj4349: 最小树形图

最小树形图模板题…… 这种\(O(nm)\)的东西真的能考到么…… #include <bits/stdc++.h> #define N 60 #define INF 1000000000 using namespace std; int n, m, nn; double ai[N], an[N], ci[2][N][N], ans; int bc[N]; int ini[N], vis[N], inc[N], inl[N]; int dfn; int dfs(int t) { vis[t]