HDU-4126 Genghis Khan the Conqueror 树形DP+MST (好题)
题意:给出一个n个点m条边的无向边,q次询问每次询问把一条边权值增大后问新的MST是多少,输出Sum(MST)/q。
解法:一开始想的是破圈法,后来想了想应该不行,破圈法应该只能用于加边的情况而不是修改边,因为加边可以保证以前MST不用的边加边之后也一定不用,但是修改边不能保证以前不用的边修改边之后会不会再用。
正解是参考https://blog.csdn.net/Ramay7/article/details/52236040这位大佬的。

大佬真的分析得巨好。我的理解就是:假如我们要计算dp[u][v]代表去掉MST上u-v这条边之后能替代的最好边,设u这一边的连通点集是(u1,u2,u3...),v这一边的点集是(v1,v2,v3...),那么我们朴素算法是暴力枚举每一对ui和vi然后取最小值,显然这样超时。用树形DP的方法是,我们枚举一个根节点rt,然后dfs一边计算以rt为根节点的时候的MST的所有边的dp值,计算方式就是dp[u][v]=min(dis[y][rt])(即子树中到根rt的最小值)。枚举完根节点rt之后我们的dp数组就出来了。 为什么这样能达到朴素算法一样的效果呢?因为考虑我们每一次rt对dp[u][v]的贡献,显然每一个rt都是在点集(u1,u2,u3...)中的,然后这次dfs可以计算(u1,u2,u3...)中的某一个ui和所有的(v1,v2,v3...)的点对对答案的贡献,然后所以的rt加起来必定等于(u1,u2,u3...)。 这里说得有点乱了,就是这样:
(rt=u1)x(v1,v2,v3...)+(rt=u2)*(v1,v2,v3...)+(rt=u3)*(v1,v2,v3...)+....(rt=ui)*(v1,v2,v3...) == (u1,u2,u3...)*(v1,v2,v3...) (上面说的一大堆想说的就是这个等式的意思qwq)
最后处理下询问看看修改边在不在原MST上,就可以获得AC了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=3e3+;
int n,m,fa[N],dis[N][N],dp[N][N];
LL sum,ans;
struct edge{
int x,y,z;
bool operator < (const edge &rhs) const {
return z<rhs.z;
}
}e[N*N];
bool mst[N][N]; int cnt,head[N],nxt[N<<],to[N<<];
void add_edge(int x,int y) {
nxt[++cnt]=head[x]; to[cnt]=y; head[x]=cnt;
} int getfa(int x) { return x==fa[x] ? x : fa[x]=getfa(fa[x]); } void Kruskal() {
sort(e+,e+m+);
for (int i=;i<=n;i++) fa[i]=i;
int num=;
for (int i=;i<=m;i++) {
int fx=getfa(e[i].x),fy=getfa(e[i].y);
if (fx==fy) continue;
fa[fx]=fa[fy];
add_edge(e[i].x,e[i].y); add_edge(e[i].y,e[i].x);
mst[e[i].x][e[i].y]=mst[e[i].y][e[i].x]=;
sum+=e[i].z;
if (++num==n) break;
}
} int dfs(int rt,int x,int fa) {
int Min=0x3f3f3f3f;
for (int i=head[x];i;i=nxt[i]) {
int y=to[i];
if (y==fa) continue;
int tmp=dfs(rt,y,x);
Min=min(Min,tmp);
dp[x][y]=min(dp[x][y],tmp); //用子树的Min更新dp[][]
dp[y][x]=min(dp[y][x],tmp);
}
if (dis[rt][x] && !mst[rt][x]) Min=min(Min,dis[rt][x]); //更新Min
return Min;
} int main()
{
while (scanf("%d%d",&n,&m) && n) {
cnt=; for (int i=;i<=n;i++) head[i]=;
for (int i=;i<=n;i++) for (int j=;j<=n;j++) dis[i][j]=mst[i][j]=,dp[i][j]=0x3f3f3f3f;
for (int i=;i<=m;i++) {
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
e[i].x++; e[i].y++;
dis[e[i].x][e[i].y]=dis[e[i].y][e[i].x]=e[i].z;
}
sum=; ans=;
Kruskal(); for (int i=;i<=n;i++) dfs(i,i,); //每个点做根节点dfs一次 int q; scanf("%d",&q);
for (int i=;i<=q;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
x++; y++;
if (!mst[x][y]) ans+=sum; //不在MST上
else { //在MST上
LL tdis=sum-dis[x][y]+min(z,dp[x][y]);
ans+=tdis;
}
}
printf("%.4lf\n",(double)ans/q);
}
return ;
}
HDU-4126 Genghis Khan the Conqueror 树形DP+MST (好题)的更多相关文章
- HDU 4126 Genghis Khan the Conqueror (树形DP+MST)
题意:给一图,n个点,m条边,每条边有个花费,给出q条可疑的边,每条边有新的花费,每条可疑的边出现的概率相同,求不能经过原来可疑边 (可以经过可疑边新的花费构建的边),注意每次只出现一条可疑的边,n个 ...
- 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条边中的一条) 表示改动边权. (数据保证改动后的边权比原先的边权大) 问:改动后的最小生成树的权 ...
- 「日常训练」 Genghis Khan the Conqueror(HDU-4126)
题意 给定\(n\)个点和\(m\)条无向边(\(n\le 3000\)),需要将这\(n\)个点连通.但是有\(Q\)次(\(Q\le 10^4\))等概率的破坏,每次破坏会把\(m\)条边中的某条 ...
- 刷题总结——Genghis Khan the Conqueror (hdu4126)
题目: Genghis Khan(成吉思汗)(1162-1227), also known by his birth name Temujin(铁木真) and temple name Taizu(元 ...
- HDU 1520.Anniversary party 基础的树形dp
Anniversary party Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- HDU 3586 Information Disturbing(二分+树形dp)
http://acm.split.hdu.edu.cn/showproblem.php?pid=3586 题意: 给定一个带权无向树,要切断所有叶子节点和1号节点(总根)的联系,每次切断边的费用不能超 ...
- HDU 5682 zxa and leaf 二分 树形dp
zxa and leaf 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5682 Description zxa have an unrooted t ...
- HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过 ...
随机推荐
- [Luogu1938][USACO09NOV]找工就业Job Hunt
原题链接:https://www.luogu.org/problem/show?pid=1938 这一道题有一个比较难的点就是,这一张图上,是点上有权.既然点上有权的话,我们就不好一下子使用最短路了. ...
- python之 matplotlib模块之绘制堆叠柱状图
我们先来看一个结果图 看到这个图,我个人的思路是 1 设置标题 import numpy as np import matplotlib.pyplot as plt plt.title('Scores ...
- 【leetcode】891. Sum of Subsequence Widths
题目如下: 解题思路:题目定义的子序列宽度是最大值和最小值的差,因此可以忽略中间值.首先对数组排序,对于数组中任意一个元素,都可以成为子序列中的最大值和最小值而存在.例如数组[1,2,3,4,5,6] ...
- Vue学习笔记-父子通信案例
<div id="app"> <cpn :number1="num1" :number2="num2" @num1chan ...
- 【LeetCode 60】第k个排列
题目链接 [题解] 逆康托展开. 考虑康托展开的过程. K = ∑v[i]*(n-i)! 其中v[i]表示在a[i+1..n]中比a[i]小的数字的个数 (也即未出现的数字中它排名第几(从0开始)) ...
- Android逆向之旅---SO(ELF)文件格式详解
第一.前言 从今天开始我们正式开始Android的逆向之旅,关于逆向的相关知识,想必大家都不陌生了,逆向领域是一个充满挑战和神秘的领域.作为一名Android开发者,每个人都想去探索这个领域,因为一旦 ...
- linux 基础命令总结
1.mkdir 创建目录 -p 创建多级目录 mkdir -p /data/test -m, --mode=模式 设置权限模式(类似chmod),而不是rwxrwxrwx 减umask -p, --p ...
- Delphi Base64编码/解码
Uses CnBase64: CnBase64.Base64Encode(Edit1.Text, Psw64);
- HBuilder的一些常用快捷键
Alt + [ 匹配括号 Alt + ↓跳转到下一个可编辑区Ctrl + Alt + j 合并下一行Ctrl + Alt + ←选择助手Ctrl + 回车 换行Ctrl + Shift + 回车 向上 ...
- mac 上查看python3的各种安装路径
1.mac chromedriver的安装目录:/usr/local/bin 2.mac htmltestrunner的存放目录:命令行下 import sys sys.path/Library/Fr ...