hdu4126Genghis Khan the Conqueror
来源:互联网 发布:九年级下册历史书淘宝 编辑:程序博客网 时间:2024/04/26 18:39
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4126
题意:给定n个点的m条边,其中有q条边中的一条一定会变大(每一条变大的概率相同),求变大之后最小生成树边权和的期望。
分析:最小生成树+树形dp的好题。首先我们要确定最初的最小生成树是有哪些边组成的,然后对于每一条可能变大的边进行判断,这样变大的边就会被分为两类A:变大的边不是最小生成树中的边,这时候显然最小生成树的权值和是不会变的,因为这条变大的边还是不会被加入到最小生成树中。B:变大的边恰好是最小生成树中的一条,这时候我们就得删掉原来这条边的权值,这样的话树中重新变成了两颗子树,我们应该继续用这条变大了的边还是在之前就没有用到的边中选一条最优的呢?这就是我们要解决的问题了。我们设dp[i][j]表示i不在以j为根的子树中时i通过没有用过的边距离j子树中所有点中的最小值,那么有dp[i][j]=min(dis[i][j],dis[i][k]),k是j的儿子并且要求i到这些点直接的边在最小生成树中没用过,我们反过来就能求出DP[j]=min(dp[i][j])表示去掉j与j的父亲间的边时最小的备用边,处理出来DP数组我们就能O(1)解决每个询问啦。O(n^2)
代码:
#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<vector>#include<string>#include<stdio.h>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=3010;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=1000000007;const int INF=1000000010;const ll MAX=1000000000;const double pi=acos(-1.0);typedef double db;typedef unsigned long long ull;ll sum,ans;bool q[N][N],bo[N];int n,m,tot,u[N],v[2*N],pre[2*N];int in[N],out[N],fa[N],DI[N],dis[N][N],dp[N][N],DP[N];void add(int a,int b) { v[tot]=b;pre[tot]=u[a];u[a]=tot++; v[tot]=a;pre[tot]=u[b];u[b]=tot++;}void dfs(int a,int b) { in[a]=++tot;fa[a]=b; for (int i=u[a];i!=-1;i=pre[i]) if (v[i]!=b) dfs(v[i],a); out[a]=tot; for (int i=1;i<=n;i++) if (!(in[i]>=in[a]&&out[i]<=out[a])) { if (!q[i][a]) dp[i][a]=dis[i][a]; for (int j=u[a];j!=-1;j=pre[j]) if (!q[i][v[j]]&&v[j]!=b) dp[i][a]=min(dp[i][a],dp[i][v[j]]); }}void init() { int i,j,x,y,z; for (i=1;i<=n;i++) for (j=1;j<=n;j++) dis[i][j]=1e8; for (i=1;i<=n;i++) dis[i][i]=0; for (i=1;i<=m;i++) { scanf("%d%d%d", &x, &y, &z); x++;y++;dis[x][y]=dis[y][x]=z; }}void prim() { int i,j,w,mi; memset(q,0,sizeof(q)); for (i=1;i<=n;i++) q[i][i]=1; tot=0;sum=0; memset(u,-1,sizeof(u)); memset(bo,0,sizeof(bo)); for (i=1;i<=n;i++) fa[i]=1,DI[i]=dis[1][i]; for (i=1;i<=n;i++) { w=0;mi=1e8; for (j=1;j<=n;j++) if (!bo[j]&&DI[j]<mi) w=j,mi=DI[j]; sum+=mi;bo[w]=1;add(w,fa[w]); q[w][fa[w]]=q[fa[w]][w]=1; for (j=1;j<=n;j++) if (dis[w][j]<DI[j]) DI[j]=dis[w][j],fa[j]=w; }}void deal() { int i,j; for (i=1;i<=n;i++) for (j=1;j<=n;j++) dp[i][j]=1e8; for (i=1;i<=n;i++) in[i]=out[i]=-1; tot=0;dfs(1,1); for (i=1;i<=n;i++) DP[i]=1e8; for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (!(in[j]>=in[i]&&out[j]<=out[i])) DP[i]=min(DP[i],dp[j][i]);}void query() { int i,x,y,z; scanf("%d", &m);ans=0; for (i=1;i<=m;i++) { scanf("%d%d%d", &x, &y, &z); x++;y++; if (!q[x][y]) ans+=sum; else if (fa[x]==y) ans+=sum-dis[x][y]+min(DP[x],z); else ans+=sum-dis[x][y]+min(DP[y],z); } printf("%.4f\n", 1.0*ans/m);}int main(){ while (scanf("%d%d", &n, &m)&&(n||m)) { init();prim(); deal();query(); } return 0;}
0 0
- hdu4126Genghis Khan the Conqueror
- hdu4126Genghis Khan the ConquerorGenghis Khan the Conqueror(MST+树形DP)
- HDU4126Genghis Khan the Conqueror(最小生成树+并查集)
- hdu4126Genghis Khan the Conqueror (最小生成树+树形dp)
- hdu4126.Genghis Khan the Conqueror
- hdu4126.Genghis Khan the Conqueror
- Genghis Khan the Conqueror HDU
- hdu 4126 Genghis Khan the Conqueror
- HDU 4126 Genghis Khan the Conqueror
- Genghis Khan the Conqueror----HDU_4126----最小生成树_DFS_DP
- HDU_4126 Genghis Khan the Conqueror 最小生成树
- hdu 4126 Genghis Khan the Conqueror 最小生成树变形
- 树形dp+MST-hdu-4126-Genghis Khan the Conqueror
- hdu 4126 Genghis Khan the Conqueror (MST+树形dp)
- HDU 4126 Genghis Khan the Conqueror MST+最佳替代边
- hdu4126 Genghis Khan the Conqueror 树形dp+最小生成树
- HDU 4126 Genghis Khan the Conqueror MST+树形dp
- HDU 4126 Genghis Khan the Conqueror (树形DP + MST)
- Halcon中二维码解析函数解码率和时长的优化方法
- HDU 5802 Windows 10(贪心+DFS)
- ButterKnife使用详解
- 集合----链式存储的实现
- NSDate
- hdu4126Genghis Khan the Conqueror
- 用 GIT 把代码部署到服务器上
- 利用python找房子
- redis通过SLAVEOF命令进行主从配置
- 提高 Vim 和 Shell 效率的 9 个建议
- NopCommerce使用Autofac实现依赖注入
- 虚拟机中 yum 安装时报错
- css中em单位的用法
- 今日开始学习C++