题目请戳这里

题目大意:给n个点,m条边,每条边权值c,现在要使这n个点连通。现在已知某条边要发生突变,再给q个三元组,每个三元组(a,b,c),(a,b)表示图中可能发生突变的边,该边一定是图中的边。c表示该边新的权值,c只可能比原来的权值大。给的q条边发生突变的概率是一样的。求突变后连通n个点最小代价期望值。

题目分析:如果没有那条突变的边,就是求一个mst。但是因为有一条边要突变,每条边突变的概率相同,都为1/q。所以要枚举所有的q条边,求出该边突变后最小生成树代价。q条边分2类:一类是生成树中的边,第二类不是生成树中的边。

第二类边很好处理,既然本身不是生成树中的边。那么这条边突变后权值变大,现在要使权值最小,这条边不选就是了,所以总代价依然是原图的mst。

第一类边发生突变的话,那么去掉这条边后原来的mst就被分成了2个子树,所以我们要找到解决办法就是寻找这2个子树之间的次短边(最小边是去掉的那条生成树中的边)。比较一下,如果这条次短边的权值小于这条突变的生成树上的边,那么就要换掉这条边,否则保留。

现在的关键是求去掉某条边生成树边后,2个子树的最小距离。很容易想到一个O(n^3)的算法:枚举每条生成树边(u,v),分别从u和v开始沿着生成树边遍历,求出两两点间最小值。可是复杂度未免太高。借助dp的思想,可以将这个过程复杂度降一个n。

考虑次过程的这样一个性质:求某个点i到以点j为根的树的最短距离=min(i到j所有子树的最短距离,i到j的最短距离),那么可以枚举起点i,从i点开始沿着mst的边dfs,每经过一条边,那么这条边可以将n个点分成2部分,一部分含i,另一部分不含i(废话),利用dfs的性质,对于从i出发沿着生成树的边遍历到的每个点,当要离开这个点的时候,保证其所有的子树都已经遍历完毕,那么i到j的子树的最短距离就确定了,那么以到达j的边为割边,i到j这颗子树的最短距离就有了。每一次从i点的dfs表示的是枚举割边后包含i的子树和不包含i的子树之间的最小距离。枚举每个点,就能得到对于所有生成树的边,dp[u][v]表示以(u,v)为割边的两颗子树的最短距离。

好NB的DP!

汉语组织的可能不是很好,具体画图吧,好容易懂的。

详情请见代码:

  1. #include <iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 3005;
  7. const int M = 1000005;
  8. const int inf = 0x3f3f3f3f;
  9. int dp[N][N],dis[N][N],cost[N][N],lowcost[N],pre[N];
  10. bool used[N][N],flag[N];
  11. int head[N],num;
  12. double ans;
  13. int n,m,q,mst;
  14. struct node
  15. {
  16. int to,next;
  17. }e_mst[M];
  18. void build(int s,int e)
  19. {
  20. e_mst[num].to = e;
  21. e_mst[num].next = head[s];
  22. head[s] = num ++;
  23. }
  24. void prim()
  25. {
  26. int i,j;
  27. mst = 0;
  28. memset(flag,false,sizeof(flag));
  29. for(i = 0;i < n;i ++)
  30. {
  31. lowcost[i] = dis[0][i];
  32. pre[i] = 0;
  33. }
  34. flag[0] = true;
  35. for(i = 1;i < n;i ++)
  36. {
  37. int minn = inf;
  38. int v;
  39. for(j = 0;j < n;j ++)
  40. {
  41. if(lowcost[j] < minn && flag[j] == false)
  42. {
  43. minn = lowcost[j];
  44. v = j;
  45. }
  46. }
  47. mst += minn;
  48. used[pre[v]][v] = used[v][pre[v]] = true;
  49. build(pre[v],v);
  50. build(v,pre[v]);
  51. flag[v] = true;
  52. for(j = 0;j < n;j ++)
  53. {
  54. if(flag[j] == false && lowcost[j] > dis[v][j])
  55. {
  56. lowcost[j] = dis[v][j];
  57. pre[j] = v;
  58. }
  59. }
  60. }
  61. }
  62. int dfs(int cur,int u,int fa)//用cur更新cur点所在的子树和另外子树的最短距离
  63. {
  64. int ret = inf;
  65. for(int i = head[u];~i;i = e_mst[i].next)//沿着生成树的边遍历
  66. {
  67. if(e_mst[i].to == fa)
  68. continue;
  69. int tmp = dfs(cur,e_mst[i].to,u);//用cur更新的以当前边(u,e_mst[i].to)为割边的两个子树最短距离
  70. ret = min(tmp,ret);//以(fa,u)为割边的2个子树的最短距离
  71. dp[u][e_mst[i].to] = dp[e_mst[i].to][u] = min(dp[u][e_mst[i].to],tmp);
  72. }
  73. if(fa != cur)//生成树边不更新
  74. ret = min(ret,dis[cur][u]);
  75. return ret;
  76. }
  77. void solve()
  78. {
  79. int i,j;
  80. int a,b,c;
  81. int sum = 0;
  82. memset(head,-1,sizeof(head));
  83. num = 0;
  84. prim();
  85. for(i = 0;i < n;i ++)
  86. dfs(i,i,-1);
  87. scanf("%d",&q);
  88. for(i = 0;i < q;i ++)
  89. {
  90. scanf("%d%d%d",&a,&b,&c);
  91. if(used[a][b])
  92. {
  93. if(c < dp[a][b])
  94. sum += (mst - dis[a][b] + c);
  95. else
  96. sum += (mst - dis[a][b] + dp[a][b]);
  97. }
  98. else
  99. sum += mst;
  100. }
  101. ans = (double)sum/(double)q;
  102. printf("%.4lf\n",ans);
  103. }
  104. int main()
  105. {
  106. int i,j,a,b,c;
  107. while(scanf("%d%d",&n,&m),(m + n))
  108. {
  109. for(i = 0;i < n;i ++)
  110. for(j = 0;j < n;j ++)
  111. {
  112. dp[i][j] = inf;
  113. used[i][j] = false;
  114. if(i == j)
  115. dis[i][j] = 0;
  116. else
  117. dis[i][j] = inf;
  118. }
  119. for(i = 0;i < m;i ++)
  120. {
  121. scanf("%d%d%d",&a,&b,&c);
  122. dis[a][b] = dis[b][a] = c;
  123. }
  124. solve();
  125. }
  126. return 0;
  127. }
  128. //921MS 80028K

hdu4126Genghis Khan the ConquerorGenghis Khan the Conqueror(MST+树形DP)的更多相关文章

  1. HDU 4126 Genghis Khan the Conqueror MST+树形dp

    题意: 给定n个点m条边的无向图. 以下m行给出边和边权 以下Q个询问. Q行每行给出一条边(一定是m条边中的一条) 表示改动边权. (数据保证改动后的边权比原先的边权大) 问:改动后的最小生成树的权 ...

  2. HDU 4126 Genghis Khan the Conqueror 最小生成树+树形dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4126 Genghis Khan the Conqueror Time Limit: 10000/50 ...

  3. hdu4756 Install Air Conditioning(MST + 树形DP)

    题目请戳这里 题目大意:给n个点,现在要使这n个点连通,并且要求代价最小.现在有2个点之间不能直接连通(除了第一个点),求最小代价. 题目分析:跟这题一样样的,唉,又是原题..先求mst,然后枚举边, ...

  4. hdu4126Genghis Khan the Conqueror (最小生成树+树形dp)

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submiss ...

  5. MST + 树形 dp

    Genghis Khan(成吉思汗)(1162-1227), also known by his birth name Temujin(铁木真) and temple name Taizu(元太祖), ...

  6. hdu 4756 MST+树形dp ****

    题意:给你n(n = 1000)个二维点,第一个点是power plant,还有n - 1个点是dormitories.然后现在知道有一条寝室到寝室的边是不能连的,但是我们不知道是哪条边,问这种情况下 ...

  7. HDU 4756 Install Air Conditioning (MST+树形DP)

    题意:n-1个宿舍,1个供电站,n个位置每两个位置都有边相连,其中有一条边不能连,求n个位置连通的最小花费的最大值. 析:因为要连通,还要权值最小,所以就是MST了,然后就是改变一条边,然后去找出改变 ...

  8. hdu4126(MST + 树形dp

    题意:       这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少. 思路:(prim+树形dp)       先跑一边 ...

  9. HDU-4126 Genghis Khan the Conqueror 树形DP+MST (好题)

    题意:给出一个n个点m条边的无向边,q次询问每次询问把一条边权值增大后问新的MST是多少,输出Sum(MST)/q. 解法:一开始想的是破圈法,后来想了想应该不行,破圈法应该只能用于加边的情况而不是修 ...

随机推荐

  1. [React Testing] The Redux Store - Multiple Actions

    When using Redux, we can test that our application state changes are working by testing that dispatc ...

  2. TypedArray和obtainStyledAttributes使用

    在编写Android自定义按钮示例基础上,如果要指定字体大小产生这样的效果: 其实是不需要自定义变量的,可以直接使用TextView的配置属性: <com.easymorse.textbutto ...

  3. 大数据笔记09:大数据之Hadoop的HDFS使用

    1. HDFS使用: HDFS内部中提供了Shell接口,所以我们可以以命令行的形式操作HDFS

  4. 网页HTML1

    表格表单 表格, <tabale>    -------表格 <tr>            --------------行 <td>             -- ...

  5. javascript 识别移动端设备

    看到一种比较简单的方法,于是就把它记录下来备用吧.最近离职了,房子换了,还有...真是一把心酸,我知道谁活着都不容易,自己也资格把自己的苦水吐给别人,因为别人也过得不容易,所以大多不快都只能闷着,大家 ...

  6. C#异步编程的实现方式——ThreadPool线程池

    在需要创建的线程很多,且都是比较小的线程的情况下,可以使用线程池(ThreadPool类).ThreadPool是一个静态方法,提供了对一个线程集合的操作,它会在线程数不足时增加线程,空闲线程数过多时 ...

  7. (转)弹出窗口lhgDialog API文档

    应用到你的项目 如果您使用独立版本的lhgDialog窗口组件,您只需在页面head中引入lhgcore.lhgdialog.min.js文件,4.1.1+版本做了修改可以和jQuerya库同时引用, ...

  8. 如何获取外网Ip呢, 终于找到方法了

    临时更换网址:http://20140507.ip138.com/ic.asp 这个网址能同时获取ip和城市名字 上面的网址如何来的呢,其实很简单,随便打开一个获取Ip的网站,比如http://www ...

  9. POJ1995 Raising Modulo Numbers(快速幂)

    POJ1995 Raising Modulo Numbers 计算(A1B1+A2B2+ ... +AHBH)mod M. 快速幂,套模板 /* * Created: 2016年03月30日 23时0 ...

  10. js判断一个变量是否为数组的解决方案

    前端开发中,在做项目的时候,我们经常需要对一个变量进行数组类型的判断,当然即使你暂时没遇到,但是这个问题也是大家去面试时的高频问题,有必要拿出来说一说. 大家都知道js中可以使用typeof来判断变量 ...