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 founder of the Mongol Empire and the greatest conqueror in Chinese history. After uniting many of the nomadic tribes on the Mongolian steppe, Genghis Khan founded a strong cavalry equipped by irony discipline, sabers and powder, and he became to the most fearsome conqueror in the history. He stretched the empire that resulted in the conquest of most of Eurasia. The following figure (origin: Wikipedia) shows the territory of Mongol Empire at that time. 

Our story is about Jebei Noyan(哲别), who was one of the most famous generals in Genghis Khan’s cavalry. Once his led the advance troop to invade a country named Pushtuar. The knights rolled up all the cities in Pushtuar rapidly. As Jebei Noyan’s advance troop did not have enough soldiers, the conquest was temporary and vulnerable and he was waiting for the Genghis Khan’s reinforce. At the meantime, Jebei Noyan needed to set up many guarders on the road of the country in order to guarantee that his troop in each city can send and receive messages safely and promptly through those roads.

There were N cities in Pushtuar and there were bidirectional roads connecting cities. If Jebei set up guarders on a road, it was totally safe to deliver messages between the two cities connected by the road. However setting up guarders on different road took different cost based on the distance, road condition and the residual armed power nearby. Jebei had known the cost of setting up guarders on each road. He wanted to guarantee that each two cities can safely deliver messages either directly or indirectly and the total cost was minimal.

Things will always get a little bit harder. As a sophisticated general, Jebei predicted that there would be one uprising happening in the country sooner or later which might increase the cost (setting up guarders) on exactly ONE road. Nevertheless he did not know which road would be affected, but only got the information of some suspicious road cost changes. We assumed that the probability of each suspicious case was the same. Since that after the uprising happened, the plan of guarder setting should be rearranged to achieve the minimal cost, Jebei Noyan wanted to know the new expected minimal total cost immediately based on current information.

Input

There are no more than 20 test cases in the input. 
For each test case, the first line contains two integers N and M (1<=N<=3000, 0<=M<=N×N), demonstrating the number of cities and roads in Pushtuar. Cities are numbered from 0 to N-1. In the each of the following M lines, there are three integers xi, yi and ci(ci<=107), showing that there is a bidirectional road between xi and yi, while the cost of setting up guarders on this road is ci. We guarantee that the graph is connected. The total cost of the graph is less or equal to 109.

The next line contains an integer Q (1<=Q<=10000) representing the number of suspicious road cost changes. In the following Q lines, each line contains three integers Xi, Yi and Ci showing that the cost of road (Xi, Yi) may change to Ci (Ci<=107). We guarantee that the road always exists and Ci is larger than the original cost (we guarantee that there is at most one road connecting two cities directly). Please note that the probability of each suspicious road cost change is the same.

Output

For each test case, output a real number demonstrating the expected minimal total cost. The result should be rounded to 4 digits after decimal point.

Sample Input

3 3

0 1 3

0 2 2

1 2 5

3

0 2 3

1 2 6

0 1 6

0 0

Sample Output

6.0000

题意:

改变其中一条边的权值时的最小生成树的权值和的平均值;

思路:

求一次最小生成树,再看改变的边是否为最小生成树上的边,不是的话还是取最小生成树的值,在上面的话变成了求两棵子树的最短距离,然后就巴拉巴拉一堆;搞了一夜晚还没怎么搞懂;

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N=9e6+4;
typedef long long ll;
const ll mod=1e9+7;
const int inf=1e9;
const double PI=acos(-1.0);
int n,m,dis[3002][3002],p[3002],vis[3002],u,v,w,flag[3002][3002],dp[3002][3002];
struct Edge
{
    int l,r,len;
};
Edge edge[N];
int cmp(Edge x,Edge y)
{
    return x.len<y.len;
}
int findset(int x)
{
    if(x==p[x])return x;
    return p[x]=findset(p[x]);
}
int same(int x,int y)
{
    int fx=findset(x),fy=findset(y);
    if(fx!=fy)p[fx]=fy;
}
vector<int>vc[3002];
int dfs(int num,int x,int father)
{
    int l=vc[x].size();
    int ans=inf;
    for(int i=0;i<l;i++)
    {
        int y=vc[x][i];
        if(y!=father)
        {
            int temp=dfs(num,y,x);ans=min(ans,temp);
            dp[x][y]=dp[y][x]=min(dp[y][x],temp);

        }
    }
    if(num!=father)
    {
        ans=min(ans,dis[num][x]);
    }
    return ans;
}
int main()
{
    while(1)
    {
        scanf("%d%d",&n,&m);
        if(n==0&&m==0)break;
        for(int i=0;i<n;i++)
        {
            vc[i].clear();
            p[i]=i;
            for(int j=0;j<n;j++)
            {
                flag[i][j]=0;
              dis[i][j]=dp[i][j]=inf;
            }
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            edge[i].l=u;
            edge[i].r=v;
            edge[i].len=w;
            dis[u][v]=w;
            dis[v][u]=w;
        }
        sort(edge,edge+m,cmp);
        double mans=0;
        for(int i=0;i<m;i++)
        {
            if(findset(edge[i].l)!=findset(edge[i].r))
            {
                same(edge[i].l,edge[i].r);
                flag[edge[i].l][edge[i].r]=1;
                flag[edge[i].r][edge[i].l]=1;
                mans+=(double)edge[i].len;
                vc[edge[i].l].push_back(edge[i].r);
                vc[edge[i].r].push_back(edge[i].l);
            }
        }
        for(int i=0;i<n;i++)
        {
            dfs(i,i,-1);
        }
        int q;
        scanf("%d",&q);
        double sum=0;
        for(int i=0;i<q;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            if(!flag[u][v])sum+=mans;
            else
            {
                sum+=mans-dis[u][v]*1.0+min(dp[u][v],w)*1.0;

            }
        }
        printf("%.4lf\n",sum/(q*1.0));
    }

    return 0;
}
时间: 2024-07-30 13:49:55

hdu-4126 Genghis Khan the Conqueror(最小生成树+树形dp)的相关文章

HDU 4126 Genghis Khan the Conqueror MST+树形dp

题意: 给定n个点m条边的无向图. 下面m行给出边和边权 下面Q个询问. Q行每行给出一条边(一定是m条边中的一条) 表示修改边权. (数据保证修改后的边权比原先的边权大) 问:修改后的最小生成树的权值是多少. 每个询问互相独立(即每次询问都是对于原图修改) 保证没有重边. 求:所有修改后的最小生成树权值的平均值. 思路: 首先跑一个最小生成树. 求得这个MST的权值 int mst; 对于每个询问(u.v,dis); 若(u,v) 不是MST上的边,则此时的权值就是 mst 否则我们断开树边(

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+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(包

HDU4126Genghis Khan the Conqueror(最小生成树+并查集)

Genghis Khan the Conqueror Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 1687    Accepted Submission(s): 501 Problem Description Genghis Khan(成吉思汗)(1162-1227), also known by his birth name

Install Air Conditioning HDU - 4756(最小生成树+树形dp)

Install Air Conditioning HDU - 4756 题意是要让n-1间宿舍和发电站相连 也就是连通嘛 最小生成树板子一套 但是还有个限制条件 就是其中有两个宿舍是不能连着的 要求所有情况中最大的那个 这是稠密图 用kruskal的时间会大大增加 所以先跑一遍prim 跑完之后对最小生成树里面的边去搜索(树形dp)我觉得dp就是搜索(虽然我菜到切不了dp题.) so dfs的过程我也叫做树形dp咯 dp[i][j]表示i和j不相连后 这两个部分距离最小的边 代码如下 #incl

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 序上:其实那个第一条边一定连