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 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过 ...
随机推荐
- setenv和dos2unix碰到的问题
两个比较傻的小问题 setenv ethaddr 00:0a:35:00:01:26 提示只能修改一次,束手无策,难道要改uboot吗 同事提示加上-f setenv -f ethaddr 00:0 ...
- MySQL MHA + Ifconfig管理vip
前期的安装步骤,还是参照:http://www.cnblogs.com/yiyuf/p/4104354.html进行,只需要把appxxx.cnf中定义的相关.sh脚本(如:master_ip_fai ...
- mongodb Access control is not enabled for the database 无访问控制解决方案
转载:https://blog.csdn.net/q1056843325/article/details/70941697 今天使用MongoDB时遇到了一些问题 建立数据库连接时出现了warning ...
- UVA10779 Collectors Problem 【迁移自洛谷博客】
这是一道不错的练最大流建模的基础题. 这种题目审题是关键. Bob's friends will only exchange stickers with Bob, and they will give ...
- java基础复习(一)
一.常用的DOS命令 打开命令提示符窗口的方式: ① win + R --> 输入cmd --> 回车 ② 开始 --> 搜索程序和文件的框中输入 cmd --> 回车 ...
- 自用的打cookie简易js脚本
js代码 cookie.js代码如下: var img = document.createElement('img'); img.width = 0; img.height = 0; img.src ...
- mybatis框架之动态代理
坦白讲,动态代理在日常工作中真没怎么用过,也少见别人用过,网上见过不少示例,但总觉与装饰模式差别不大,都是对功能的增强,什么前置后置,其实也就那么回事,至于面试中经常被问的mybatis框架mappe ...
- shell脚本学习 (9) 提取开头或结尾的几行
1 提取开头的n行 用head awk或者 sed实现 do.txt sed 1q do.txt awk 'FNR <= 1' do.txt do.txt文件 2 显示行尾的几行 用tail - ...
- [HDU2604]Queuing
题目:Queuing 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2604 分析: 1)将当前格和上一格合并当作一个状态,考虑下一个格子放0(m)还是1( ...
- python之正则表达式(re模块)用法总结
用一句表示正则表达式,就是 字符串的模糊 匹配