警察叔叔就是这个人!

给定一个无向有权图,首先一个最小生成树 MST,从 MST 中选取一个度数大于 1 的点 作为根 K,使每颗子树及该子树到根的边权之和方差最小。输出 K 和最小方差的值。

对于60%的数据:3 ≤ N ≤ 2,000,N-1 ≤ M ≤ 50,000

对于100%的数据:3 ≤ N ≤ 40,000,N-1 ≤ M ≤ 200,000

对于100%的数据:0 < len ≤ 100,000,000

首先肯定要搞MST。。。数据大所以kruska

然后dfs把MST搞成一个有根树

有根树上记每个点记以它为根的子树权值和

枚举每一个点,和它连通的部分就是它的每一个子树和整棵树除了它所在的子树以外的各个部分

算一下方差就OJBK

#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
const int INF=2147493233;
using namespace std;
int n,m;
struct edge
{
    int from,to;
    double v;
    bool operator<(const edge &b)const
    {
        return v<b.v;
    }
}edg[439677];
int ans,cnt;
int fa[439600];
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
bool same(int x,int y){return find(x)==find(y);}
void link(int x,int y){fa[find(x)]=find(y);}
int first[80010],to[80010],next[80010];
double val[80010];
bool tag[40010];
double dp[40010];
bool vis[40010];
int master[40010];
int rank[40010];
inline void add(int u,int v,double w)
{
    to[++cnt]=v;
    next[cnt]=first[u];
    first[u]=cnt;
    val[cnt]=w;
    
    to[++cnt]=u;
    next[cnt]=first[v];
    first[v]=cnt;
    val[cnt]=w;
}
void kruskal()
{
    for(int i=0;i<=439600;i++)fa[i]=i;
    sort(edg+1,edg+m+1);
    for(int i=1;i<=m;i++)
    {
        int u=find(edg[i].from),v=find(edg[i].to);
        if(u!=v)
        {
            fa[u]=v;
            add(edg[i].from,edg[i].to,edg[i].v);
        }
    }
}
void dfs(int x)
{
    if(vis[x])return;
    vis[x]=1;
    for(int i=first[x];i;i=next[i])
    {
        if(!vis[to[i]])
        {
            rank[x]++;
            dfs(to[i]);
            master[to[i]]=x;
            dp[x]+=(dp[to[i]]+val[i]);
        }    
    }
}
int a,b;
double c;
int main()
{
    double ans=2147483233.0;
    int Ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lf",&a,&b,&c);
        edg[i]=(edge){a,b,c};
    }
    kruskal();
    dfs(1);
    for(int i=n;i>=1;i--)
    {
        int crt=rank[i]+(master[i]!=0);
        if(crt<2)continue;
        double sum=0,avg=dp[1]/crt,res=dp[1]-dp[i];
        for(int j=first[i];j;j=next[j])
        {
            if(to[j]!=master[i])sum+=(double)(val[j]+dp[to[j]]-avg)*(val[j]+dp[to[j]]-avg);
            if(i!=1)sum+=(res-avg)*(res-avg);
        }
        if(sum<ans)
        {
            ans=sum;
            Ans=i;
        }
    }
    cout<<Ans;
    return 0;
}
View Code

 

posted @ 2017-10-23 16:40  探险家Mr.H  阅读(492)  评论(0编辑  收藏  举报