树形dp+MST-hdu-4126-Genghis Khan the Conqueror
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4126
题目意思:
给一图,n个点,m条边,每条边有个花费,给出q条可疑的边,每条边有新的花费,每条可疑的边出现的概率相同,求不能经过原来可疑边(可以经过可疑边新的花费构建的边),注意每次只出现一条可疑的边,n个点相互连通的最小花费的期望。
解题思路:
树形dp+MST。
先用kruskal算法找到最小生成树,并求出总花费sum.
再以枚举n个点,依次作为树根dfs,dp[i][j]表示<i,j>为最小生成树上的边,且去掉该边后,包括点i的连通块中的点集A到包括点j的连通块点集B的最小距离。
对于根节点为ro,边为<i,j>的dp[i][j]=min(以j节点为根的子树到ro的最短距离,dp[i][j]).
如下图所示:
以右边点集为子树求出左边点集中每个点作为树根时到all的最小距离。其实对于上面那条边,只用枚举ro个点就行了,但是不好确定每条边的ro集,所以枚举n个点,作为ro,然后dfs,最每条边更新一次,时间复杂度为o(n^2)可以接受。
代码:
- #include<iostream>
- #include<cmath>
- #include<cstdio>
- #include<cstdlib>
- #include<string>
- #include<cstring>
- #include<algorithm>
- #include<vector>
- #include<map>
- #include<set>
- #include<stack>
- #include<list>
- #include<queue>
- #include<ctime>
- #define eps 1e-6
- #define INF 0x3f3f3f3f
- #define PI acos(-1.0)
- #define ll __int64
- #define lson l,m,(rt<<1)
- #define rson m+1,r,(rt<<1)|1
- #pragma comment(linker, "/STACK:1024000000,1024000000")
- using namespace std;
- #define Maxn 3300
- struct Edge
- {
- int a,b,c;
- }edge[Maxn*Maxn]; //保存边的信息
- int dis[Maxn][Maxn]; //原始距离
- bool hav[Maxn][Maxn]; //是否为最小生成树上的边
- int fa[Maxn],dp[Maxn][Maxn];//dp[i][j]表示<i,j>为最小生成树上的边,且去掉该边后,包括点i的连通块中的点集A到包括点j的连通块点集B的最小距离。
- int n,m,cnt;
- ll sum;
- int find(int x) //并查集
- {
- int tmp=x;
- while(x!=fa[x])
- x=fa[x];
- while(fa[tmp]!=x)
- {
- int tt=fa[tmp];
- fa[tmp]=x;
- tmp=tt;
- }
- return x;
- }
- bool cmp(struct Edge a,struct Edge b)
- {
- return a.c<b.c;
- }
- struct EE //构建最小生成树
- {
- int v;
- struct EE * next;
- }ee[Maxn<<1],*head[Maxn<<1];
- void add(int a,int b)
- {
- ++cnt;
- ee[cnt].v=b;
- ee[cnt].next=head[a];
- head[a]=&ee[cnt];
- }
- void kruskal() //克鲁斯卡尔算法求最小生成树
- {
- sum=0;
- cnt=0;
- for(int i=1;i<=m;i++)
- {
- int a=find(edge[i].a),b=find(edge[i].b);
- if(a!=b)
- {
- fa[b]=edge[i].a;
- sum+=edge[i].c;
- hav[edge[i].a][edge[i].b]=hav[edge[i].b][edge[i].a]=true;
- add(edge[i].a,edge[i].b); //建树
- add(edge[i].b,edge[i].a);
- }
- }
- }
- int dfs(int ro,int fa,int cur,int dep) //表示以cur作为当前子树根中所有子树节点到总根ro的最短距离
- {
- struct EE * p=head[cur];
- int mi=INF;
- if(dep!=1) //不为树根的儿子
- mi=dis[cur][ro];
- while(p)
- {
- int v=p->v;
- if(v!=fa)
- {
- int tt=dfs(ro,cur,v,dep+1);
- mi=min(mi,tt);
- dp[cur][v]=dp[v][cur]=min(dp[v][cur],tt);//更新当前边
- }
- p=p->next;
- }
- return mi;
- }
- int main()
- {
- // printf("%d\n",INF);
- while(scanf("%d%d",&n,&m)&&n+m)
- {
- memset(dis,INF,sizeof(dis));
- for(int i=1;i<=m;i++)
- {
- int a,b,c;
- scanf("%d%d%d",&a,&b,&c);
- edge[i].a=a,edge[i].b=b,edge[i].c=c;
- dis[a][b]=dis[b][a]=c;
- }
- sort(edge+1,edge+m+1,cmp);
- for(int i=0;i<n;i++)
- fa[i]=i;
- memset(hav,false,sizeof(hav));
- memset(head,NULL,sizeof(head));
- kruskal();
- memset(dp,INF,sizeof(dp));
- for(int i=0;i<n;i++) //以每个点最为树根,对每条边更新n次
- dfs(i,i,i,0);
- ll ans=0;
- int q;
- scanf("%d",&q);
- for(int i=1;i<=q;i++)
- {
- int a,b,c;
- scanf("%d%d%d",&a,&b,&c);
- if(hav[a][b]) //是最小生成树上的边
- {
- int tt=min(dp[a][b],c); //要么用新边,要么用不是最小生成树上的边
- ans=ans+sum-dis[a][b]+tt;
- }
- else //不是最小生成树上的边,直接用最小生成树
- ans=ans+sum;
- // printf("*%lf\n",ans);
- }
- printf("%.4f\n",ans*1.0/q);
- }
- return 0;
- }
树形dp+MST-hdu-4126-Genghis Khan the Conqueror的更多相关文章
- HDU 4126 Genghis Khan the Conqueror 最小生成树+树形dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4126 Genghis Khan the Conqueror Time Limit: 10000/50 ...
- HDU 4126 Genghis Khan the Conqueror MST+树形dp
题意: 给定n个点m条边的无向图. 以下m行给出边和边权 以下Q个询问. Q行每行给出一条边(一定是m条边中的一条) 表示改动边权. (数据保证改动后的边权比原先的边权大) 问:改动后的最小生成树的权 ...
- HDU 4126 Genghis Khan the Conqueror (树形DP+MST)
题意:给一图,n个点,m条边,每条边有个花费,给出q条可疑的边,每条边有新的花费,每条可疑的边出现的概率相同,求不能经过原来可疑边 (可以经过可疑边新的花费构建的边),注意每次只出现一条可疑的边,n个 ...
- HDU-4126 Genghis Khan the Conqueror 树形DP+MST (好题)
题意:给出一个n个点m条边的无向边,q次询问每次询问把一条边权值增大后问新的MST是多少,输出Sum(MST)/q. 解法:一开始想的是破圈法,后来想了想应该不行,破圈法应该只能用于加边的情况而不是修 ...
- 刷题总结——Genghis Khan the Conqueror (hdu4126)
题目: Genghis Khan(成吉思汗)(1162-1227), also known by his birth name Temujin(铁木真) and temple name Taizu(元 ...
- UVA- 1504 - Genghis Khan the Conqueror(最小生成树-好题)
题意: n个点,m个边,然后给出m条边的顶点和权值,其次是q次替换,每次替换一条边,给出每次替换的边的顶点和权值,然后求出这次替换的最小生成树的值; 最后要你输出:q次替换的平均值.其中n<30 ...
- uvalive 5834 Genghis Khan The Conqueror
题意: 给出一个图,边是有向的,现在给出一些边的变化的信息(权值大于原本的),问经过这些变换后,MST总权值的期望,假设每次变换的概率是相等的. 思路: 每次变换的概率相等,那么就是求算术平均. 首先 ...
- 【Uvalive 5834】 Genghis Khan the Conqueror (生成树,最优替代边)
[题意] 一个N个点的无向图,先生成一棵最小生成树,然后给你Q次询问,每次询问都是x,y,z的形式, 表示的意思是在原图中将x,y之间的边增大(一定是变大的)到z时,此时最小生成数的值是多少.最后求Q ...
- 「日常训练」 Genghis Khan the Conqueror(HDU-4126)
题意 给定\(n\)个点和\(m\)条无向边(\(n\le 3000\)),需要将这\(n\)个点连通.但是有\(Q\)次(\(Q\le 10^4\))等概率的破坏,每次破坏会把\(m\)条边中的某条 ...
- 【树形DP】 HDU 2412 Party at Hali-Bula
给出根节点(BOSS) 然后还有N-1个边 A B 由B指向A (B为A 的上司) 每次仅仅能选择这个关系中的当中一个 求最多选几个点 而且输出是不是唯一的 重点推断是否唯一: 1.若下属不去和去都 ...
随机推荐
- 妹子图太多怎么看才好,Swing来支招
近期事少,翻开非常久曾经写的小程序,创意倒是尚可,代码写的却比較基础,非常多东西没有实现,略改了改形成了如今的模样,如今大家都忙着大数据,中间件,web开发,偶尔看看Java Swing的作品,也许能 ...
- 详解Android Handler的使用-别说你不懂handler(转)
我们进行Android开发时,Handler可以说是使用非常频繁的一个概念,它的用处不言而喻.本文就详细介绍Handler的基本概念和用法. Handler的基本概念 Handler主 ...
- 安装Stomp扩展时错误提示error: 'zend_class_entry' has no member named 'default_properties'
在安装stomp扩展时, 有这样的提示 error: 'zend_class_entry' has no member named 'default_properties' 交待下安装上下文, sto ...
- asp.net错误日志写入
当我们一个web项目开发已完成,测试也通过了后,就把他放到网上去,但是,bug是测不完的,特别是在一个大的网络环境下.那么,我们就应该记录这些错误,然后改正.这里,我的出错管理页面是在global.a ...
- editplus双击单词语法高亮显示设置
view=>Word Highlighting
- c# 学习笔记(二)
c#3.0 新特性 扩展方法 扩展方法允许编写和声明它的类之外的关联类的方法 用于没有源代码或者类是密封的,需要给类扩展新方法时 1.扩展方法必须被声明为static2.扩展方法声明所在的类必须被声 ...
- EBS基础—表的后缀
1._ALL或无后缀:基表,所有对数据操作最终都是对基表的操作,表包含所有不同经营单位的信息,多组织环境. 2._B/_T:也是一种基表.一些数据和验证存储在此表中. 3._TL:语言的基表,TL表支 ...
- 对C#泛型实例化对像--转
最近在编写一套开发框架结构主要应用.Net 3.5以上的框架开发与应用.在此框架中应用了较多的泛型.下面来讲讲对泛型的实例化,以代码为例,如: public class A { } public cl ...
- 设置windows窗口ICON 【windows 编程】【API】【原创】
1. ICON介绍 最近开始接触windows 编程,因此将自己所接触的一些零散的知识进行整理并记录.本文主要介绍了如何更改windows对话框窗口的ICON图标.这里首先介绍一下windows IC ...
- 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object
有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...