题目链接:

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. Swoole源代码学习记录(十五)——Timer模块分析

    swoole版本号:1.7.7-stable Github地址:点此查看 1.Timer 1.1.swTimer_interval_node 声明: // swoole.h 1045-1050h ty ...

  2. 不可错过的手机APP常见8种界面导航样式

    前言:相信每个移动开发project师都会遇到,当一个项目开发启动时,须要考虑搭建怎么的框架.一个好的框架.也会决定着一个APP的前途与命运.框架的风格,如今常见的有八种:标签导航.舵式导航.抽屉导航 ...

  3. 【剑指Offer学习】【面试题43 : n 个锻子的点数】

    题目:把n个骰子扔在地上,全部骰子朝上一面的点数之和为s.输入n.打印出s 的全部可能的值出现的概率. 解题思路 解法一:基于通归求解,时间效率不够高. 先把n个骰子分为两堆:第一堆仅仅有一个.还有一 ...

  4. Codeforces Round #291 (Div. 2) C - Watto and Mechanism 字符串

    [题意]给n个字符串组成的集合,然后有m个询问(0 ≤ n ≤ 3·105, 0 ≤ m ≤ 3·105) ,每个询问都给出一个字符串s,问集合中是否存在一个字符串t,使得s和t长度相同,并且仅有一个 ...

  5. ubuntu 安装eclipse

    安装步骤: 一.下载客户端: 解压放到,/opt/Java/eclipse目录下,解压方法参考上一篇文章<ubuntu 配置Java jdk> 二.打开eclipse: 打开终端,输入,c ...

  6. win10的独立存储

    win10的独立存储和win8的大致相同 Windows.Storage.ApplicationDataContainer roamingSettings = Windows.Storage.Appl ...

  7. 基于CANVAS与MD5的客户端生成验证码

    好久没写东西,工作太忙了!不想服务端请求太多,搞了个这玩意儿,不过项目中并不会用上,还是使用服务端生成的机制(会安全多少呢?):我就想问个问题,除了图像识别来破解这样的简单验证码外,针对我这种例子,可 ...

  8. CSS 让标点符号不出现在行首

    word-break:break-all; 这条语句的作用是让语句到达边界的时候自动换行,但是正是这个样式让标点符号跑到了行首. 语法: word-break : normal | break-all ...

  9. android自定义listview实现圆角

    在项目中我们会经常遇到这种圆角效果,因为直角的看起来确实不那么雅观,可能大家会想到用图片实现,试想上中下要分别做三张图片,这样既会是自己的项目增大也会增加内存使用量,所以使用shape来实现不失为一种 ...

  10. Oracle oerr使用

    [oracle@cuug ~]$ oerr ora 01555 01555, 00000, "snapshot too old: rollback segment number %s wit ...