hdu4126Genghis Khan the Conqueror (最小生成树+树形dp)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 2524    Accepted Submission(s): 760


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 x i, y i and c i(c i<=10 7), showing that there is a bidirectional road between x i and y i, while the cost of setting up guarders on this road is c i. We guarantee that the graph is connected. The total cost of the graph is less or equal to 10 9.

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 X i, Y i and C i showing that the cost of road (X i, Y i) may change to C i (C i<=10 7). We guarantee that the road always exists and C i 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
Hint
The initial minimal cost is 5 by connecting city 0 to 1 and city 0 to 2. In the first suspicious case, the minimal total cost is increased to 6; the second case remains 5; the third case is increased to 7. As the result, the expected cost is (5+6+7)/3 = 6.
题意:一个N个点的无向图,先生成一棵最小生成树,边上有权值,然后给你Q次询问,每次询问都是x,y,z的形式,表示的意思是在原图中将x,y之间的边增大(一定是变大的)到z时,此时最小生成树里边的值是多少,让你求Q次询问最小生成树的平均值。 
思路:先求出最小生成树,用dp[i][j]表示如果i,j不连接(前提是i,j是一条边上,且在最小生成树中),每次选择一个点作为根节点,用它和一个点的连线来更新dp[i][j],具体看代码,主要参照http://www.cnblogs.com/-sunshine/archive/2013/01/11/2855689.html这个博客的,写的很详细。
#include <vector>
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=3000+5;
const int inf=1000000000;
struct edge{
    int u,v,w;
}e[N*N];//所有的边
int n,m,q;
int a,b,c;
int father[N];
int map[N][N];//map[i][j]表示(i,j)边权值
int dp[N][N];//dp[i][j]表示去掉MST上的(i,j)边后的最佳替换边的长度
bool vis[N][N];//标记是否在MST上
vector<int> Edge[N];
int min(int a,int b){return a<b?a:b;}
int find(int x){
    if(x!=father[x])
        father[x]=find(father[x]);
    return father[x];
}
//用于Kruskal使用
int cmp(edge e1,edge e2){
    return e1.w<e2.w;
}
//更新dp[i][j],对于i点为根的除j之外的所有子树中的所有的点到j距离的最小值
//确定这些点和j不在一个集合里
int dfs(int rt,int u,int fa){//求rt点到以u为根的树及其子树的最小距离
    int ans=inf;
    for(int i=0;i<Edge[u].size();i++){
        int v=Edge[u][i];
        if(v==fa) continue;
        int tmp=dfs(rt,v,u);
        ans=min(ans,tmp);
        dp[u][v]=dp[v][u]=min(dp[u][v],tmp);//注意,这里更新的是u,v
        //通过dfs的返回值来更新dp[i][j]
    }
    if(rt!=fa) //保证这条边不是生成树的边,不然不能更新
        ans=min(ans, map[rt][u]);
    return ans;
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0&&m==0) break;
        double mst=0,sum=0;
        for(int i=0;i<n;i++){
            Edge[i].clear();
            father[i]=i;
            for(int j=0;j<n;j++)
                map[i][j]=dp[i][j]=inf,
                vis[i][j]=1;
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            map[e[i].u][e[i].v]=map[e[i].v][e[i].u]=e[i].w;
        }
        sort(e,e+m,cmp);
        for(int i=0;i<m;i++){
            a=find(e[i].u);
            b=find(e[i].v);
            if(a!=b){
                father[a]=b;
                mst+=e[i].w;
                Edge[e[i].u].push_back(e[i].v),
                Edge[e[i].v].push_back(e[i].u);
                vis[e[i].u][e[i].v]=vis[e[i].v][e[i].u]=0;
            }
        }
        for(int i=0;i<n;i++){
            dfs(i,i,-1);
        }
        scanf("%d",&q);
        for(int i=0;i<q;i++){
            scanf("%d%d%d",&a,&b,&c);
            if(vis[a][b]==1)
                sum+=mst;
            else
                sum+=mst*1.0-map[a][b]+min(dp[a][b],c);
        }
        printf("%.4lf\n",sum/(double)q);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值