HDU 4126 Genghis Khan the Conqueror MST+树形dp

题意:

给定n个点m条边的无向图。

下面m行给出边和边权

下面Q个询问。

Q行每行给出一条边(一定是m条边中的一条)

表示修改边权。

(数据保证修改后的边权比原先的边权大)

问:修改后的最小生成树的权值是多少。

每个询问互相独立(即每次询问都是对于原图修改)

保证没有重边。

求:所有修改后的最小生成树权值的平均值。

思路:

首先跑一个最小生成树。

求得这个MST的权值 int mst;

对于每个询问(u.v,dis);

若(u,v) 不是MST上的边,则此时的权值就是 mst

否则我们断开树边(u,v),然后找u点集和v点集之间的边中权值最小的边cost[u][v];

这样当前的权值就是 mst - g[u][v] + min(cost[u][v], dis);

剩下就是如何计算cost;

MST会求得一个无根树。

我们把无根树转成以u为根时 ,对于v子树其实是不变的。

剩下就是简单dp了

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <queue>
#include <algorithm>
#include <cmath>
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
typedef long long ll;
using namespace std;
const ll inf = 100000000;
const int N = 3005;
ll g[N][N], d[N], mst, cost[N][N];
bool vis[N], choose[N][N];
int n, m;
vector<int> G[N];
ll dfs(int u, int fa, int src){
    ll siz = inf;
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        if(v == fa)continue;
        ll tmp = dfs(v, u, src);
        siz = min(siz, tmp);
        cost[u][v] = cost[v][u] = min(cost[u][v], tmp);
    }
    if(fa != src)
        siz = min(siz, g[u][src]);
    return siz;
}
int pre[N];
void MST(){
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            cost[i][j] = g[i][j] = inf, choose[i][j] = 0;

    while(m--){
        int u, v; ll dis; rd(u);rd(v); rd(dis);
        g[u][v] = g[v][u] = min(g[u][v], dis);
    }
    for(int i = 0; i < n; i++)
    {
        d[i] = inf;
        G[i].clear();
        vis[i] = 0;
        pre[i] = -1;
    }
    d[0] = 0;
    mst = 0;
    for(int i = 0; i < n; i++)
    {
        int pos = -1;
        for(int j = 0; j < n; j++)
            if(!vis[j] &&(pos == -1 || d[pos] > d[j]))
                pos = j;
        if(pre[pos]!=-1)
        {
            G[pos].push_back(pre[pos]);
            G[pre[pos]].push_back(pos);
            choose[pos][pre[pos]] = choose[pre[pos]][pos] = 1;
        }
        for(int j = 0; j < n; j++)
            if(d[j] > g[j][pos])
            {
                d[j] = g[j][pos];
                pre[j] = pos;
            }
        vis[pos] = 1;
        mst += d[pos];
    }
}

int main() {
    int q, u, v; ll dis;
	while(cin>>n>>m, n+m) {
        MST();
        for(int i = 0; i < n; i++)
            dfs(i, -1, i);
        rd(q);
        ll ans = 0;
        for(int i = 1; i <= q; i++) {
            rd(u); rd(v); rd(dis);
            if(choose[u][v] == false)
                ans += mst;
            else
                ans += mst - g[u][v] + min(cost[u][v], dis);
        }
        printf("%.4f\n",(double)ans/(double)q);
	}
	return 0;
}
时间: 2024-08-02 10:57:40

HDU 4126 Genghis Khan the Conqueror MST+树形dp的相关文章

hdu 4126 Genghis Khan the Conqueror hdu 4756 Install Air Conditioning 最小生成树

这两题思路一样.先说下题意. 第一道就是一张图,q个操作,每次将一个边x,y增大到z,求出此时的最小生成树的值w,输出这q个w的平均值. 第二道是一张完全图,但是有一条未知边不能选,求最小生成树最大可能是多少. 对于第一道题,先求出最小生成树,对于每个操作x,y,z,假设x,y不是树边,那么w不变,如果是树边,那么假设这条边连接了u,v两个点集,那么只要添上一条两个点集间所有边的最小的那条即可.但是复杂度为n3,所以为了降低复杂度,要预处理出这条最小边,用dp[ i ][ j ]表示i,j两集合

hdu-4126 Genghis Khan the Conqueror(最小生成树+树形dp)

题目链接: Genghis Khan the Conqueror Time Limit: 10000/5000 MS (Java/Others)   Memory Limit: 327680/327680 K (Java/Others) Problem Description Genghis Khan(成吉思汗)(1162-1227), also known by his birth name Temujin(铁木真) and temple name Taizu(元太祖), was the fo

HDU 4126 Genghis Khan the Conqueror (树形DP+MST)

题意:给一图,n个点,m条边,每条边有个花费,给出q条可疑的边,每条边有新的花费,每条可疑的边出现的概率相同,求不能经过原来可疑边 (可以经过可疑边新的花费构建的边),注意每次只出现一条可疑的边,n个点相互连通的最小花费的期望. 析:要想连通先让他们连通起来,先构造出一个MST,然后再暴力,如果这个边不在这里面,那么花费不变,如果在里面,那我们需要知道是用原来的边最少, 还是再找一条边使他们连通起来,这里就要先预处理了,dp[i]j[i] 表示 左边的那个一半 i 和 右边那一半 j 的最长距离

hdu4126 Genghis Khan the Conqueror Prim + 树形dp

好题,学到了很多新姿势. 题意:在一棵mst上,修改一些边的值(此边有可能不在MST上),Q次操作(每次只是在原图上修改),求修改后的MST总和. 题解:首先Prim 求出MST    (n^2) 对于每次修改,即相当于把MST上一条边截掉,原来的MST变成了两棵树,可以证明修改后的新MST一定包含这两棵树,也就是说只需要找到连接两棵树的最短边即可. 好了,关键问题就是怎样找连接两棵树上的最短边.可以用(n^2)的dp进行预处理,然后每次o(1)查询即可. 我们用dp[i][j] 表示 树A(包

HDU 1561 The more, The Better(树形dp+背包)

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6000    Accepted Submission(s): 3548 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物.但由于地理位置原因,有些城堡不能直接攻

hdu 1520 Anniversary party(第一道树形dp)

传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1520 Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16376    Accepted Submission(s): 6241 Problem Description There is going to

hdu 5909 Tree Cutting——点分治(树形DP转为序列DP)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5909 点分治的话,每次要做一次树形DP:但时间应该是 siz*m2 的.可以用 FWT 变成 siz*mlogm ,但这里写的是把树变成序列来 DP 的方法,应该是 nlogn*m 的. 树上的一个点,如果选,就可以选它的孩子,所以它向它的第一个孩子连边:如果不选,就会跳到它的下一个兄弟或者是父亲的下一个兄弟之类的,向那边连一条边. 做出树的 dfs 序,把边都连在 dfs 序上:其实那个第一条边一定连

HDU 1520 Anniversary party(DFS或树形DP)

Problem Description There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E.

HDU 4126 POJ 4006 Genghis Khan the Conqueror

题意: n(3000)个点的图  q(10^4)次操作  每次操作从原图更改一条边的权值  问q次操作后最小生成树的平均值是多少 思路: 先求最小生成树  然后讨论  如果更改的不是树边  则最小生成树不变  如果是树边  就要选择原图中的非树边和更改后的这条边其中较小的一个形成新树 难做的只有"是树边"这种情况  我们考虑  原图中的非树边与原树一定可以形成一个环  那么我们可以这样理解  只要断掉的边是环内的树边  那么都可以用这条非树边补上形成新树  也就是说  这条非树边覆盖了