Codeforces 437D The Child and Zoo


Codeforces 437D The Child and Zoo
title gist: There is a connected graph, and each point has a corresponding value. Define the cost of one of the paths from point p to point q as the minimum value of the path points . Define f(p,q) as the maximum cost of all paths from point p to point q . Accumulate f(p,q) for each pair of p,q and take the average.
At first glance it looks like a search of the graph, but the process of searching for the sum will definitely time out. This question cleverly uses the union check set , so make a simple record.
Idea: Define the weight of the edge as the smaller value between two points, and sort the edge in descending order. After sorting, the two points of each edge are checked and maintained. Because of the sorting, it can be guaranteed that when the sets to which the two points belong are merged, num[u] num[w] v is obtained by two pairs of points in the two sets The sum of the combined f(u,w), and the cost of the path taken is the value of the minimum point, and it is the largest cost of all paths, which is also the ingeniousness of the personal feeling to change the solution (where num[i] represents size of the set rooted at i). All in all, I feel that the transformation of this question to the problem is really interesting.
PS: It should be noted that the intermediate process may overflow when accumulating, so one of the numbers can be forced to be converted to double, so that the other numbers can be promoted with the type to prevent overflow.
Code:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<climits>
using namespace std;
typedef long long ll;
typedef map<char,int> M;
typedef queue<int> Q;
typedef vector<int> V;
typedef pair<int,int> P;
const int maxn=5*100000;
int a[maxn],p[maxn],num[maxn];//num[i]表示根为i的集合的大小 
struct edge
{
    int u,w,v;
};
bool cmp(const edge& a,const edge& b)
{
    return a.v>b.v;
}
edge e[maxn];
double sum=0;
void init(int n)
{
    for (int i=0;i<=n;++i)
    {
        p[i]=i;
        num[i]=1;
    }
    return;
}
int find(int x)
{
    if (p[x]==x)
        return x;
    return p[x]=find(p[x]); 
}
void unite(int x,int y,int v) //合并两点所属集合称为一个新的连通块
{
    x=find(x);
    y=find(y);
    if (x!=y)
    {
        sum+=double(v)*num[x]*num[y];
        p[x]=y;
        num[y]+=num[x];
        return;
    }
    return;
}
int main()
{
    int i,j,n,m,t,k;
    cin>>n>>m;
        //输入
    for (i=1;i<=n;++i)
        scanf("%d",&a[i]);
    for (i=0;i<m;++i)
    {
        int u,w;
        scanf("%d%d",&u,&w);
        e[i].u=u;
        e[i].w=w;
        e[i].v=min(a[u],a[w]);
    }
        //初始化
    init(n);
        //降序排序
    sort(e,e+m,cmp);
        //维护边的两点
    for (i=0;i<m;++i)
    {
        unite(e[i].u,e[i].w,e[i].v);
    }
    printf("%.6lf",sum/(double(n)*(n-1)/2.0));
    return 0;
}
 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325091281&siteId=291194637