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 }
时间: 2024-10-06 16:34:25

HDU 6141 I am your Father!(最小树形图+权值编码)的相关文章

朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】

什么是最小树形图?相信大家如果会过来看这篇文章,想必也应该对最小生成树有所了解的,最小生成树求的是无向图的一颗生成树的最小权值.我们的最小树形图就是来解决一个有向图的一颗生成树的最小权值,对于度娘来说,最小树形图是这样定义的:最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小. 通解最小树形图的一种算法是是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法:朱.刘算法. 今天我们就来浅谈一下最小树形图的问题. 大题上完整的朱

hdu 3072 有向图缩点成最小树形图计算最小权

题意,从0点出发,遍历所有点,遍历边时候要付出代价,在一个SCC中的边不要付费.求最小费用. 有向图缩点(无需建立新图,,n<=50000,建则超时),遍历边,若不在一个SCC中,用一个数组更新记录最小到达该连通分量的最小边权即可...边聊天,边1A,哈哈... #include<iostream> #include<stack> #include<queue> #include<cstdio> #include<cstring> usin

HDU 6141 I am your Father!(最小树形图)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6141 [题目大意] 给出一个有向图,求1点为根的最小树形图使得第n个点的直接父亲编号最小 [题解] 如果没有第n个点直接父亲编号最小的要求, 那么只要跑一遍朱刘算法即可,考虑到直接父亲最小的条件, 我们连向第n个点的所有边进行加权操作, 使得其在总边权相同的情况选取答案具有优先性 [代码] #include <cstdio> #include <algorithm> using n

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

这个题就是需要求整个有向带权图的最小树形图,没有指定根,那就需要加一个虚根 这个虚根到每个点的权值是总权值+1,然后就可以求了,如果求出来的权值大于等于二倍的总权值,就无解 有解的情况,还需要输出最根,多解的情况,肯定是某个环上所有的点为根都可以(比如所有的点构成一个环), 这样加边的时候虚边的时候按照点的标号从小到大编,这样第一个以虚根为前驱的点也是最小的点就可以标记(标记一下) #include <iostream> #include <algorithm> #include

hdu 1565&amp;hdu 1569(网络流--最小点权值覆盖)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7717    Accepted Submission(s): 2911 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

hdu 1875 给出每个结点的坐标 权值为两点间的距离 (MST)

Sample Input2210 10 //坐标20 2031 12 21000 1000 Sample Output1414.2   //最小权值和*100  保留1位小数oh!       //不连通 prim 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <cmath> 6 # def

HDU 6214 Smallest Minimum Cut 最小割,权值编码

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6214 题意:求边数最小的割. 解法: 建边的时候每条边权 w = w * (E + 1) + 1; 这样得到最大流 maxflow / (E + 1) ,最少割边数 maxflow % (E + 1) 道理很简单,如果原先两类割边都是最小割,那么求出的最大流相等 但边权变换后只有边数小的才是最小割了 乘(E+1)是为了保证边数叠加后依然是余数,不至于影响求最小割的结果 因为假设最小割=k,那么现在新

find the most comfortable road(并差集,找差值最小的权值)

find the most comfortable road Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5359    Accepted Submission(s): 2327 Problem Description XX 星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超

HDU 3887 Counting Offspring(DFS序求子树权值和)

Problem Description You are given a tree, it's root is p, and the node is numbered from 1 to n. Now define f(i) as the number of nodes whose number is less than i in all the succeeding nodes of node i. Now we need to calculate f(i) for any possible i