题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4126

题意:给出一幅3000个点的图,有10000次操作: 求将某条边的权值变大后的最小生成树,最后输出10000次操作得到的最小生成树权值的平均值。

分析:

对于每次询问, 都是将a,b之间的边增加到c, 会出现 两种情况:

1. 如果边权增加的那条边原先就不在最小生成树中,那么这时候的最小生成树的值不变

2. 如果该边在原最小生成树中,那么这时候将增加的边从原最小生成树中去掉,这时候生成树就被分成了两个各自联通的部分,可以证明的是,这时候的最小生成树一定是将这两部分联通起来的最小的那条边。

设dp[i][j]表示去掉最小生成树中的边(i,j)分成两个联通部分后,再次将他们再次连接起来的最小的那条边长。

那么对于每点pos开始往下dfs,不断维护一个dis[pos][u](u为树上的另一点)的最小值ans,搜完子树的子节点后让最小值ans=dp[u][v],因为断开边(u,v)后靠pos连接v子树上的某一节点使得以u和v为根节点的两颗子树再次连接起来。

#pragma comment(linker,"/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define N 3010
#define FILL(a,b) (memset(a,b,sizeof(a)))
using namespace std;
struct edge
{
int u,v,w;
bool operator<(const edge &a)const
{
return w<a.w;
}
}e[N*N];
int dis[N][N],dp[N][N],vis[N][N],fa[N];
int n,m,q;
vector<int>g[N];
int find(int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void init()
{
for(int i=;i<n;i++)
{
fa[i]=i;g[i].clear();
for(int j=;j<n;j++)
dis[i][j]=dp[i][j]=inf;
}
FILL(vis,);
}
int kruskal()
{
int res=;
for(int i=;i<m;i++)
{
int a=find(e[i].u);
int b=find(e[i].v);
if(a!=b)
{
fa[a]=b;
res+=e[i].w;
vis[e[i].u][e[i].v]=vis[e[i].v][e[i].u]=;//uv这条边在最小生成树上
g[e[i].u].push_back(e[i].v);//构造最小生成树
g[e[i].v].push_back(e[i].u);
}
}
return res;
}
int dfs(int pos,int u,int fa)
{
int ans=inf;
for(int i=,size=g[u].size();i<size;i++)
{
int v=g[u][i];
if(v==fa)continue;
int mn=dfs(pos,v,u);
ans=min(ans,mn);
dp[u][v]=dp[v][u]=min(dp[u][v],mn);
}
//不断维护一个pos到v上的某一子节点的最小距离,保证边(u,v)断后ans为最优取代边,前提是(u,v)这条边不知最小生成树上
if(fa!=pos)ans=min(ans,dis[pos][u]);
return ans;
}
int main()
{
int a,b,c;
while(scanf("%d%d",&n,&m)>)
{
if(m+n==)break;
init();
for(int i=;i<m;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
dis[e[i].u][e[i].v]=dis[e[i].v][e[i].u]=e[i].w;//点u点v的距离
}
sort(e,e+m);
int mst=kruskal();
for(int i=;i<n;i++)
{
dfs(i,i,-);
}
scanf("%d",&q);
double sum=;
for(int i=;i<q;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(!vis[a][b])
{
sum+=mst;
}
else
{
sum+=mst-dis[a][b]+min(c,dp[a][b]);
}
}
printf("%.4lf\n",sum/q);
}
}

hdu4126(最小生成树+dfs)的更多相关文章

  1. HDU 5723 Abandoned country (最小生成树 + dfs)

    Abandoned country 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5723 Description An abandoned coun ...

  2. HDU 5723 Abandoned country (最小生成树+dfs)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5723 n个村庄m条双向路,从中要选一些路重建使得村庄直接或间接相连且花费最少,这个问题就是很明显的求最 ...

  3. HDU 2489 Minimal Ratio Tree 最小生成树+DFS

    Minimal Ratio Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  4. CodeForces160D 最小生成树 + dfs

    https://cn.vjudge.net/problem/26727/origin 题目大意: 给一个带权的无向图,保证没有自环和重边. 由于最小生成树不唯一,因此你需要确定每一条边是以下三种情况哪 ...

  5. 【BZOJ3551】[ONTAK2010]Peaks加强版 最小生成树+DFS序+主席树

    [BZOJ3545][ONTAK2010]Peaks Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困 ...

  6. BZOJ1016:[JSOI2008]最小生成树计数(最小生成树,DFS)

    Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...

  7. $bzoj1016-JSOI2008$ 最小生成树计数 最小生成树 $dfs/matrix-tree$定理

    题面描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的).由于不同的 ...

  8. HDU 4081 Peach Blossom Spring (最小生成树+dfs)

    题意:给定一个 n 个点和相应的权值,要求你用 n-1 条边连接起来,其中一条边是魔法边,不用任何费用,其他的边是长度,求该魔法边的两端的权值与其他边费用的尽量大. 析:先求出最小生成树,然后再枚举每 ...

  9. cf Inverse the Problem (最小生成树+DFS)

    题意: N个点.N行N列d[i][j]. d[i][j]:结点i到结点j的距离. 问这N个点是否可能是一棵树.是输出YES,否则输出NO. 思路: 假设这个完全图是由一棵树得来的,则我们对这个完全图求 ...

随机推荐

  1. 云计算Docker全面项目实战(Maven+Jenkins、日志管理ELK、WordPress博客镜像)

    2013年,云计算领域从此多了一个名词“Docker”.以轻量著称,更好的去解决应用打包和部署.之前我们一直在构建Iaas,但通过Iaas去实现统一功  能还是相当复杂得,并且维护复杂.将特殊性封装到 ...

  2. 基于visual Studio2013解决面试题之0609寻找链表公共节点

     题目

  3. jqueryui datepicker refresh

    http://stackoverflow.com/questions/6056287/jquery-ui-datepicker-prevent-refresh-onselect 给选中的TD加背景色

  4. Godiva_百度百科

    Godiva_百度百科 北京 三里屯 北京市朝阳区三里屯路19号院10号楼一层S10-13单元及二层S10-22单元 100027 北京朝阳大悦城北京市朝阳区朝阳北路101号朝阳大悦城1号商业楼1F- ...

  5. 使用JDBC对数据库实现批处理操作

    本篇讲述如何使用JDBC对数据库实现批处理操作.很多时候单条SQL命令不能满足我们的需求,我们需要对数据库一次实现很多操作,需要发送一批SQL命令给数据库执行. 而JDBC也提供了相应的方法给我们实现 ...

  6. 【linux】常用网站

    Kernel: http://www.kernel.org/ LSB (Linux Standard Base): http://www.linuxbase.org/ ELC(Embedded Lin ...

  7. SilkTest Q&A 9

    Q81:我应该如何存取excel sheet里面的空字符串? A81:定制代码如下: 解决方案1: [-] if sText!=NULL [ ] Page.tfldName.SetText(sText ...

  8. hdu 4687 Boke and Tsukkomi

    Dancing link twice. Find the maximum combination numbers in the first time. Enumerate each node, dan ...

  9. 源代码编译lamp环境

    没有办法用 rpm查询一个源代码包是否安装 因为 并不是用rpm安装的 可以先吧 selinux 给禁用掉  iptables -F 把防火墙规则全部删除 首先确保 gcc  gcc-c++   ma ...

  10. c语言指针具体解释

    指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最基本的风格之中的一个.利用指针变量能够表示各种数据结构: 能非常方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编出精练而高 ...