题意

给定\(n\)个点和\(m\)条无向边(\(n\le 3000\)),需要将这\(n\)个点连通。但是有\(Q\)次(\(Q\le 10^4\))等概率的破坏,每次破坏会把\(m\)条边中的某条边的权值增大某个值,求\(Q\)次破坏每次将\(n\)个点连通的代价的期望?(全题的数据范围在int内可以过)

分析

这题是真的牛逼,我看了七八个博客都没看太明白,大多数人都没讲在点子上,但是还是有几篇博客不错的,参考如下:

参考A:https://blog.csdn.net/u014664226/article/details/49333081

参考B:https://blog.csdn.net/Anxdada/article/details/81086041

参考C:https://blog.csdn.net/ramay7/article/details/52236040 (这个是最好的,强烈推荐)

参考D:https://blog.csdn.net/gatevin/article/details/47042021 (有一些“实质上”的东西)

接下来说说我综合这些参考后自己对这题的理解与做法。

求期望的意思是,将每次破坏后的最小生成树的代价累加除以\(Q\)。然后我们仔细思考一下这个破坏。首先,如果更改发生在不是最小生成树上的边上,那么答案是不需要改变的。重点是改变发生在这棵生成树上的边中的情况下。此时这棵最小生成树会分成两棵树。显然地,新图的最小生成树一定包含这两棵树上的所有边。问题于是转化为原来的最小生成树被切成两棵树之后,如何选择权值最小的一条边将两棵树连通。

这里因此运用了树形dp。这里比较精彩:

我们记\(dp[i][j]\)是切断\((i,j)\)边后,i与j两个所在点的集合间的最短距离。但是我们不去直接这么搜索,而是去搜索i所在树的树根与j所在子树的每一个点的最短距离。于是我们将每个点当作树根进行DFS,在更新(搜索)时,我们用j所在子树所有点同root的直接距离更新掉dp数组,并有意归避掉\((i,j)\)边。可以想见,当第\(i\)轮更新完成,dp中一定保存了第1个到第\(i\)个root到他们相关点的最短距离。那么对每个点都dp过后,最后dp数组里面一定保存的就是我们要的东西了。

最后对每个查询做修正就可以了,具体见代码。真实树形dp+最小生成树好题,就是做的头疼,哈哈。

代码

/* ACM Code written by Sam X or his teammates.
* Filename: hdu4126.cpp
* Date: 2018-11-18
*/ #include <bits/stdc++.h> #define INF 0x3f3f3f3f
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
#define rep(i,a,b) for(repType i=(a); i<=(b); ++i)
#define per(i,a,b) for(repType i=(a); i>=(b); --i)
#define ZERO(x) memset(x, 0, sizeof(x))
#define MS(x,y) memset(x, y, sizeof(x))
#define ALL(x) (x).begin(), (x).end() #define QUICKIO \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0);
#define DEBUG(...) fprintf(stderr, __VA_ARGS__), fflush(stderr) using namespace std;
using pi=pair<int,int>;
using repType=int;
using ll=long long;
using ld=long double;
using ull=unsigned long long; int n,m; struct Edge
{
int u,v,w;
Edge() {}
Edge(int _u,int _v, int _w):
u(_u), v(_v), w(_w) {}
bool operator < (const Edge& rhs) const
{
if(w==rhs.w)
{
return u<rhs.u;
}
else return w<rhs.w;
}
};
const int MAXN=3005;
vector<Edge> edges;
int mat[MAXN][MAXN];
int used[MAXN][MAXN]; int edges_ord[18000005];
int pa[MAXN];
vector<Edge> nedges;
vector<int> nG[MAXN];
inline void nadd_edge(int u,int v,int w)
{
nedges.PB(u,v,w);
nG[u].PB(int(nedges.size())-1);
}
int find_pa(int x)
{
return pa[x]==x?x:pa[x]=find_pa(pa[x]);
}
inline void union_pa(int x,int y)
{
int fx=find_pa(x),
fy=find_pa(y);
if(fx!=fy) pa[fx]=fy;
}
inline int kruskal()
{
int ret=0;
iota(pa,pa+n,0);
sort(ALL(edges));
rep(i,0,edges.size()-1)
{
int u=edges[i].u,
v=edges[i].v,
w=edges[i].w;
if(find_pa(u)!=find_pa(v))
{
union_pa(u,v);
ret+=w;
used[u][v]=used[v][u]=w;
nadd_edge(u,v,w);
nadd_edge(v,u,w);
}
}
return ret;
} int dp[MAXN][MAXN];
int dfs(int root, int now, int pre)
{
//cout<<root<<" "<<now<<" "<<pre<<endl;
int ans=INF;
rep(i,0,int(nG[now].size())-1)
{
int& v=nedges[nG[now][i]].v; if(v!=pre)
{
int tmp=dfs(root,v,now);
ans=min(ans,tmp);
dp[now][v]=dp[v][now]=min(dp[now][v], tmp);
}
}
if(root!=pre && pre!=-1)
{
ans=min(ans, mat[now][root]);
}
return ans;
} inline void init()
{
edges.clear();
nedges.clear();
rep(i,0,n-1) nG[i].clear();
MS(dp,0x3f);
MS(used,-1);
MS(mat,0x3f);
} int main()
{
while(scanf("%d%d",&n,&m)==2)
{
if(!n && !m) break;
init();
rep(i,0,m-1)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edges.PB(u,v,w);
mat[u][v]=mat[v][u]=w;
}
int sum=kruskal();
rep(i,0,n-1)
dfs(i,i,-1);
int q;
scanf("%d",&q);
double ans=0;
rep(i,0,q-1)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(used[u][v]!=-1) ans+=sum-used[u][v]+min(dp[u][v], w);
else ans+=sum;
}
printf("%.4lf\n",ans/(1.0*q));
}
return 0;
}

「日常训练」 Genghis Khan the Conqueror(HDU-4126)的更多相关文章

  1. 「日常训练」ZgukistringZ(Codeforces Round #307 Div. 2 B)

    题意与分析(CodeForces 551B) 这他妈哪里是日常训练,这是日常弟中弟. 题意是这样的,给出一个字符串A,再给出两个字符串B,C,求A中任意量字符交换后(不限制次数)能够得到的使B,C作为 ...

  2. 「日常训练」 Fire!(UVA-11624)

    与其说是训练不如说是重温.重新写了Java版本的代码. import java.util.*; import java.math.*; import java.io.BufferedInputStre ...

  3. 「日常训练」COMMON 约数研究(HYSBZ-1968)

    题意与分析 感谢https://www.cnblogs.com/Leohh/p/7512960.html的题解.这题话说原来不在我的训练范围,正好有个同学问我,我就拿来做做.数学果然不是我擅长的啊,这 ...

  4. 「日常训练」 Mike and Fun (CFR305D2B)

    题意(CodeForces 548B) 每次对01矩阵中的一位取反,问每次操作后,单列中最长连续1的长度. 分析 非常非常简单,但是我当时训练的时候WA了四次...无力吐槽了,人间 不值得.jpg 代 ...

  5. 「日常训练」Common Subexpression Elimination(UVa-12219)

    今天做的题目就是抱佛脚2333 懂的都懂. 这条题目干了好几天,最后还是参考别人的代码敲出来了,但是自己独立思考了两天多,还是有收获的. 思路分析 做这条题我是先按照之前的那条题目(The SetSt ...

  6. 「日常训练」Magic Stones(CodeForces-1110E)

    题意 给定两个数组c和t,可以对c数组中的任何元素变换\(c_i\)​成\(c_{i+1}+c_{i-1}-c_i\)​,问c数组在若干次变换后能否变换成t数组. 分析 这种魔法题目我是同样的没做过. ...

  7. 「日常训练」Jongmah(Codeforces-1110D)

    题意 你有n个数字,范围[1, m],你可以选择其中的三个数字构成一个三元组,但是这三个数字必须是连续的或者相同的,每个数字只能用一次,问这n个数字最多构成多少个三元组? 分析 根据官方Editori ...

  8. 「日常训练」The Necklace(UVA-10054)

    代码 for(int i=0; i!=n; ++i) { int u = cin.nextInt(); int v = cin.nextInt(); edges.add(new Edge(u,v)); ...

  9. 「日常训练」Known Notation(ZOJ-3829)

    题意与分析 题意是这样的:给一个字符串,字符串中只包含数字和运算符'*'.现在问字符串是不是一个合法的逆波兰式(后缀表达式).已知逆波兰式的空格消除,也就是说123可以看成123也可以看成1和23.如 ...

随机推荐

  1. Codeforces Round #535 (Div. 3) E2. Array and Segments (Hard version) 【区间更新 线段树】

    传送门:http://codeforces.com/contest/1108/problem/E2 E2. Array and Segments (Hard version) time limit p ...

  2. 【洛谷P2022】有趣的数

    有趣的数 题目链接 首先求出1~k中有多少个在k前面的数的个数,若>m,则无解 比如12345,从第一位开始, 1 0~1 共2个 1-0+1 12  10~12共3个    12-10+1 1 ...

  3. HDU 1207 汉诺塔II (找规律,递推)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1207 汉诺塔II Time Limit: 2000/1000 MS (Java/Others)     ...

  4. 听说玩JAVA,必须过JDK这关?

    JDK是什么?JRE是什么?JDK和JRE的区别? Java Runtime Environment (JRE) 包含: Java虚拟机.库函数.运行Java应用程序和Applet所必须文件 Java ...

  5. Servlet Struts2 SpringMVC 获取参数与导出数据 方法比较

    servlet中通过request.getParameter()从网页获取参数 通过request session servletContext几个域对象的setAttribute(String ,O ...

  6. Java设计模式六大原则-2

    Java设计模式六大原则-2 做Java程序开发的每天都在使用JDK,Spring,SpringMvc,Mybatis,Netty,MINA等框架,但很少有人懂得背后的原理.即使打开跟下原码也是一头雾 ...

  7. C++切勿混用带符号类型和无符号类型

    如果表达式里既有带符号类型又有无符号类型,当带符号类型取值为负时会出现异常结果. 因为带符号数会自动转化为无符号数. 例如 a*b,a=-1, b=1,a是int,b是unsigned int,如果在 ...

  8. centos7 php7 动态编译mysqlnd: configure: error: Cannot find OpenSSL's <evp.h> 错误解决

    开始以为是没有安装openssl, openssl-devel,安装后发现还是提示这个错误,搜索了一下evp.h,这个文件也存在.GOOGLE 了一下,在stackoverflow,找到了答案,原来是 ...

  9. ubuntu18.04错误配置变量环境导致无法进入系统

    1.问题描述 错误配置环境变量(直接在/etc/profile文件末尾添加了export xxx),关机后一直在登录界面循环无法进入系统. ###环境变量的添加是在原有变量之后以冒号(:)分隔加入,并 ...

  10. idea 聚合项目里如果子项目引用不到父类的maven应用

    idea 聚合项目里如果子项目引用不到父类的maven应用,可以点看子类pom.xml文件,然后右键---->maven----->Reimport即可 点击右边子项目的maven---& ...