HDUOJ 2121 Ice_cream’s world II(不定根的最小树形图-好题)

举报
Linux猿 发表于 2021/08/04 23:50:24 2021/08/04
【摘要】 题目连接~~~   本题是求不定根的情况,如果以每个点为根来一次最小树形图,那必定超时。这里我们可以虚拟出来一个点作为根,然后,让这个点连接所有顶点,那边的权值是多少呢?就是所有权值和加1,这样保证了如果最小树形图存在,那么只有一条虚拟的边加入到最小树形图中,让总和减去它就可以了,还有一种情况就是如果原先图不存在最小树形图,那么有可能选择两条虚拟边加入最小树形图,只要判断...

题目连接~~~

  本题是求不定根的情况,如果以每个点为根来一次最小树形图,那必定超时。这里我们可以虚拟出来一个点作为根,然后,让这个点连接所有顶点,那边的权值是多少呢?就是所有权值和加1,这样保证了如果最小树形图存在,那么只有一条虚拟的边加入到最小树形图中,让总和减去它就可以了,还有一种情况就是如果原先图不存在最小树形图,那么有可能选择两条虚拟边加入最小树形图,只要判断一下,最后的值是否大于等于原先权值和加1的二倍,是则无解,否则存在最小树形图。那怎么求最小树形图在原先图中的根节点呢?通过上面我们知道,最后只有一个虚拟边x加入最小树形图,而这个边是加给第x-m点的边,所以在图不断变化的过程中只要记住虚拟边的边号x,然后x-m就是答案。

代码:


  
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #include <cmath>
  6. #include <ctime>
  7. #include <algorithm>
  8. using namespace std ;
  9. #define INF 0x3f3f3f3f
  10. const double esp = 0.00000001 ;
  11. const int MX = 20000 + 10 ;
  12. const int MY = 1e3 + 10 ;
  13. int tot ,f_num ;
  14. typedef struct {
  15. int u ,v ,w ;
  16. int next ;
  17. }Edge ;
  18. Edge E[MX] ;
  19. int head[MY] ,In[MY] ,pre[MY] ,Id[MY] ,vis[MY] ;
  20. void Add_edge(int u ,int v ,int w){
  21. E[tot].u = u ; E[tot].v = v ; E[tot].w = w ; E[tot].next = head[u] ; head[u] = tot++ ;
  22. }
  23. int Zhuliu(int root ,int n ,int m ,Edge E[]){
  24. int u ,v ,w ,ret = 0 ;
  25. while(1){
  26. for(int i = 0 ;i < n ; ++i)
  27. In[i] = INF ;
  28. for(int i = 0 ;i < m ; ++i){
  29. u = E[i].u ; v = E[i].v ; w = E[i].w ;
  30. if(u != v && w < In[v]){
  31. In[v] = w ;
  32. pre[v] = u ;
  33. if(u == root) f_num = i ;
  34. }
  35. }
  36. for(int i = 0 ;i < n ; ++i){
  37. if(i != root && In[i] == INF)
  38. return -1 ;//有孤立的点,没有解
  39. }
  40. int nt = 0 ;
  41. memset(Id ,-1 ,sizeof(Id)) ;
  42. memset(vis ,-1 ,sizeof(vis)) ;
  43. In[root] = 0 ;
  44. for(int i = 0 ;i < n ; ++i){
  45. ret += In[i] ;
  46. v = i ;
  47. while(vis[v] != i && Id[v] == -1 && v != root){
  48. vis[v] = i ;
  49. v = pre[v] ;
  50. }
  51. if(v != root && Id[v] == -1){
  52. for(int u = pre[v] ; u != v ; u = pre[u])
  53. Id[u] = nt ;
  54. Id[v] = nt++ ;
  55. }
  56. }
  57. if(nt == 0) break ;//没有有向环
  58. for(int i = 0 ;i < n ; ++i)
  59. if(Id[i] == -1)
  60. Id[i] = nt++ ;
  61. for(int i = 0 ;i < m ; ++i){
  62. v = E[i].v ;
  63. E[i].u = Id[E[i].u] ;
  64. E[i].v = Id[E[i].v] ;
  65. if(E[i].u != E[i].v)
  66. E[i].w -= In[v] ;
  67. }
  68. n = nt ;
  69. root = Id[root] ;
  70. }
  71. return ret ;
  72. }
  73. int main(){
  74. //freopen("input.txt" ,"r" ,stdin) ;
  75. int n , m ;
  76. while(~scanf("%d%d" ,&n ,&m)){
  77. tot = 0 ; f_num = 0 ;
  78. int sum = 1 ,u ,v ,w ;
  79. memset(head ,-1 ,sizeof(head)) ;
  80. for(int i = 0 ;i < m ; ++i){
  81. scanf("%d%d%d" ,&u ,&v ,&w) ;
  82. if(u != v){
  83. Add_edge(u ,v ,w) ;
  84. }
  85. sum += w ;//把所有的权值都加起来
  86. }
  87. for(int i = 0 ;i < n ; ++i){//再加上n条边
  88. Add_edge(n ,i ,sum) ;
  89. }
  90. int ans = Zhuliu(n ,n+1 ,n+m ,E) ;
  91. if(ans == -1 || ans >= sum*2) printf("impossible\n") ;
  92. else printf("%d %d\n" ,ans-sum ,f_num - m) ;
  93. puts("") ;
  94. }
  95. return 0 ;
  96. }


文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/52054167

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。