题目链接:

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的更多相关文章

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

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

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

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

  3. HDU 4126 Genghis Khan the Conqueror (树形DP+MST)

    题意:给一图,n个点,m条边,每条边有个花费,给出q条可疑的边,每条边有新的花费,每条可疑的边出现的概率相同,求不能经过原来可疑边 (可以经过可疑边新的花费构建的边),注意每次只出现一条可疑的边,n个 ...

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

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

  5. 刷题总结——Genghis Khan the Conqueror (hdu4126)

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

  6. UVA- 1504 - Genghis Khan the Conqueror(最小生成树-好题)

    题意: n个点,m个边,然后给出m条边的顶点和权值,其次是q次替换,每次替换一条边,给出每次替换的边的顶点和权值,然后求出这次替换的最小生成树的值; 最后要你输出:q次替换的平均值.其中n<30 ...

  7. uvalive 5834 Genghis Khan The Conqueror

    题意: 给出一个图,边是有向的,现在给出一些边的变化的信息(权值大于原本的),问经过这些变换后,MST总权值的期望,假设每次变换的概率是相等的. 思路: 每次变换的概率相等,那么就是求算术平均. 首先 ...

  8. 【Uvalive 5834】 Genghis Khan the Conqueror (生成树,最优替代边)

    [题意] 一个N个点的无向图,先生成一棵最小生成树,然后给你Q次询问,每次询问都是x,y,z的形式, 表示的意思是在原图中将x,y之间的边增大(一定是变大的)到z时,此时最小生成数的值是多少.最后求Q ...

  9. 「日常训练」 Genghis Khan the Conqueror(HDU-4126)

    题意 给定\(n\)个点和\(m\)条无向边(\(n\le 3000\)),需要将这\(n\)个点连通.但是有\(Q\)次(\(Q\le 10^4\))等概率的破坏,每次破坏会把\(m\)条边中的某条 ...

  10. 【树形DP】 HDU 2412 Party at Hali-Bula

    给出根节点(BOSS) 然后还有N-1个边  A B 由B指向A (B为A 的上司) 每次仅仅能选择这个关系中的当中一个 求最多选几个点 而且输出是不是唯一的 重点推断是否唯一: 1.若下属不去和去都 ...

随机推荐

  1. Android_硬编码设置TextView字体大小

    使用如下代码时,发现字号不会变大,反而会变小:size = (int) mText.getTextSize() + 1;mText.setTextSize(size);后来发现getTextSize返 ...

  2. Hibernate Criterion

    在查询方法设计上能够灵活的依据Criteria的特点来方便地进行查询条件的组装.Hibernate设计了CriteriaSpecification作为Criteria的父接口,以下提供了Criteri ...

  3. Android---用动画来处理布局的变化

    本文译自:http://developer.android.com/training/animation/layout.html 布局动画一种系统预装的动画,每次布局配置发生变化时,系统会运行它.你所 ...

  4. java mysql驱动

    mysql驱动方式有三种, 1.第一种是先把jar包放在项目的目录下,通过添加jar包,是使用相对地址的,这样把项目复制到其它电脑也可以用 2.第二种方法是导入外部的jar包,是绝对地址,如果项目要复 ...

  5. IDL实现主成分变化(PCA)

    IDL只能通过调用envi的二次接口做图像的变换,但是对于普通的数据没有提供函数.根据主成分变换的原理,用IDL写出来了,这样就不用每次再去用matlab的princomp去做了.主成分变化的基本过程 ...

  6. MyBatis 学习总结(二)

    1.MyBatis基础环境的搭建 1.1 核心配置文件mybatis-config.xml <?xml version="1.0" encoding="UTF-8& ...

  7. CSS对浏览器的兼容性常见处理方式小结

    CSS技巧 1.div的垂直居中问题: vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字,就垂直居中了. 缺点:要控制内 ...

  8. Mock和injectMocks的区别

    @Mock private ForeCatalogManageServiceImpl foreCatalogManageServiceImpl; 如果是上面的写法,那么 红框方法里面的代码不会执行,这 ...

  9. leetcode修炼之路——350. Intersection of Two Arrays II

    题目如下: Given two arrays, write a function to compute their intersection. Example: Given nums1 = [1, 2 ...

  10. 解决SQL Server的TEXT、IMAGE类型字段的长度限制

    更多资讯.IT小技巧.疑难杂症等等可以关注 艾康享源 微信公众号. 来自为知笔记(Wiz)