HDU 6141 I am your Father!(最小树形图+权值编码)
http://acm.hdu.edu.cn/showproblem.php?pid=6141
题意:
求最大树形图。
思路:
把边的权值变为负值,那么这就是个最小树形图了,直接套模板就可以解决。
有个问题就是n结点的父亲结点的编号要尽量小,这里有个技巧可以用,权值编码,将所有边的权值都放大1000倍,对于和n相连的边,每条边在减去(n-u)的权值。这样就会去优先考虑编号小的边,而且因为权值最大为100,所以扩大1000是不会影响结果的。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,ll> pll; 15 const int inf = 0x3f3f3f3f; 16 const int maxn=1000+5; 17 const int mod=1e9+7; 18 19 int n, m; 20 21 struct node 22 { 23 int u,v,w; 24 }edge[10*maxn]; 25 26 int pre[maxn],id[maxn],use[maxn]; 27 int in[maxn]; 28 29 int mini_tree(int root,int n,int m)//分别是树根,节点数,边数,序号从1开始 30 { 31 int ans=0; 32 int u; 33 while(true) 34 { 35 for(int i=1;i<=n;i++) in[i]=inf; 36 for(int i=1;i<=m;i++) 37 { 38 int u=edge[i].u; 39 int v=edge[i].v; 40 if(edge[i].w<in[v]&&u!=v) 41 { 42 in[v]=edge[i].w; 43 pre[v]=u; 44 } 45 }//找最小的入边 46 for(int i=1;i<=n;i++) 47 { 48 if(i==root)continue; 49 ans+=in[i];//把边权加起来 50 if(in[i]==inf)//如果存在没有入弧的点则不存在最小树形图 51 return -1; 52 } 53 memset(id,-1,sizeof(id)); 54 memset(use,-1,sizeof(use)); 55 int cnt=0; 56 for(int i=1;i<=n;i++)//枚举每个点,搜索找环 57 { 58 int v=i; 59 while(v!=root&&use[v]!=i&&id[v]==-1) 60 { 61 use[v]=i; 62 v=pre[v]; 63 } 64 if(v!=root&&id[v]==-1)//当找到环的时候缩点编号 65 { 66 ++cnt; 67 id[v]=cnt; 68 for(u=pre[v];u!=v;u=pre[u]) 69 id[u]=cnt; 70 } 71 } 72 if(cnt==0)//如果没有环结束程序 73 break; 74 for(int i=1;i<=n;i++)//把余下的不在环里的点编号 75 if(id[i]==-1) 76 id[i]=++cnt; 77 for(int i=1;i<=m;i++)//建立新的图 78 { 79 int u=edge[i].u; 80 int v=edge[i].v; 81 edge[i].u=id[u]; 82 edge[i].v=id[v]; 83 if(edge[i].u!=edge[i].v) 84 edge[i].w-=in[v]; 85 } 86 n=cnt;//更新节点数和根节点的编号 87 root=id[root]; 88 } 89 return ans; 90 } 91 92 int main() 93 { 94 //freopen("in.txt","r",stdin); 95 int T; 96 scanf("%d",&T); 97 while(T--) 98 { 99 scanf("%d%d",&n,&m); 100 for(int i=1;i<=m;i++) 101 { 102 int u,v,w; 103 scanf("%d%d%d",&u,&v,&w); 104 w*=-1000; 105 if(v==n) w-=(n-u); 106 edge[i].u=u, edge[i].v=v, edge[i].w=w; 107 } 108 int ans=mini_tree(1,n,m); 109 printf("%d %d\n",-ans/1000,n-(-ans)%1000); 110 } 111 return 0; 112 }