树形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.若下属不去和去都 ...
随机推荐
- Cocos3.0测试版发布(中文)
最新的cocos2d-x 3.0版本,我们的目标不仅是改进渲染机制,增加对2.5D的支持,基于组件的系统功能,和更好的Label功能.同时 我们希望能够进一步优化引擎,并且使用更友好的C++ API ...
- 【剑指offer】二叉树中和为某一值的路径
转载请注明出处:http://blog.csdn.net/ns_code/article/details/26141815 题目描写叙述: 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数 ...
- python 学习笔记 基础
python对象三要素: identity(值):对应于内存的地址,不可修改type(类型):不可修改value(值): mutable :可以修改 immutable:不可以修改 引用计数当引用计数 ...
- (转)cocos2dx 内存管理
原文地址:http://blog.csdn.net/ring0hx/article/details/7946397 cocos2dx的内存管理移植自Objective-C, 对于没有接触过OC的C++ ...
- javascript 鼠標拖動功能
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 这10篇 iOS 热文,你别错过哦
<移动开发必读书单> 某一领域的技术人,在他的职业生涯中,一定有一些绕不过去的技术和非技术的知识.有的时候,靠自己摸索.到处偷师,倒也能掌握.但是,这些别人早就趟过去的坎,大多已经有了非常 ...
- TwoSAT算法模板
该模板来自大白书 [解释] 给多个语句,每个语句为“ Xi为真(假) 或者 Xj为真(假)” 每个变量和拆成两个点 2*i为假, 2*i+1为真 “Xi为真 或 Xj为真” 等价于 “Xi为假 –& ...
- 使用out来返回多个值
一般的方法中,一次只能有一个返回值.但是当我们需要一个方法给我们返回多个值得时候应该怎么做呢?这时候可以使用out来修饰参数. out介绍: static void Main(string[] arg ...
- linux common command.
Stopping & Starting shutdown -h now – Shutdown the system now and do not reboothalt – Stop all p ...
- Maven Profile标签
Maven Profiles标签可以针对不同的环境来使用不同的配置文件 在发布的时候可以用 mvn release -p product mvn release -p test mvn release ...