Cotree

Cotree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 513    Accepted Submission(s): 192


Problem Description
Avin has two trees which are not connected. He asks you to add an edge between them to make them connected while minimizing the function  ni=1nj=i+1dis(i,j), where dis(i,j) represents the number of edges of the path from i to j. He is happy with only the function value.
 

 

Input
The first line contains a number  n (2<=n<=100000). In each of the following n2 lines, there are two numbers u and v, meaning that there is an edge between u and v. The input is guaranteed to contain exactly two trees.
 

 

Output
Just print the minimum function value.
 

 

Sample Input
3 1 2
 

 

Sample Output
4
 

 

Source
 

 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:   6730  6729  6728  6727  6726 
题目大意:输入N N-2条边 保证两棵树 要求你把两棵树连起来 使得一棵树上任意两个点之间距离和最小
思路:求出两颗树的重心,连起来,dfs求路径和就行了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int INF=1e9+7;
LL N;
int cnt=0,sum=0;
LL mi,pos;
LL head[maxn<<1];
LL sonnum[maxn<<1],sonmax[maxn<<1];//每科子树节点的个数 子树节点中最大的结点个数 
bool vis[maxn];
LL ans=0;
struct Edge
{
    int next,to;
}e[maxn<<1];
void dfs(int root,int pre)
{
    vis[root]=true;
    sum++;//算总共有多少个点
    sonnum[root]=1;
    for(int i=head[root];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre) continue;
        dfs(v,root);
        sonnum[root]+=sonnum[v];
        sonmax[root]=max(sonmax[root],sonnum[v]);//节点数最大的子树
    }
}
void add_edge(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void getroot(int root,int pre,int n)
{
    for(int i=head[root];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre) continue;
        getroot(v,root,n);
    }
    int ma=max(sonmax[root],n-sonnum[root]);
    if(mi>ma)
    {
        mi=ma;pos=root;
    }
}
void solve(int root,int pre)
{
    sonnum[root]=1;
    for(int i=head[root];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==pre) continue;
        solve(v,root);
        sonnum[root]+=sonnum[v];

    }
    ans+=(LL)sonnum[root]*(LL)(N-sonnum[root]);//算每条边用过的次数
}
int main()
{
    memset(head,-1,sizeof(head));
    memset(sonmax,0,sizeof(sonmax));
    memset(sonnum,0,sizeof(sonnum));
    scanf("%lld",&N);
    for(int i=1;i<=N-2;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        add_edge(u,v);//链式前向星存图
        add_edge(v,u);
    }
    mi=INF;
    dfs(1,0);//任选一颗树 进行遍历
    int sum1=sum;//这棵树有多少个结点 
    getroot(1,0,sum1);//求出这棵树的重心
    int root1=pos;//重心
    int node;
    for(int i=1;i<=N;i++)//找到另一颗树上的点
    {
        if(!vis[i])
        {
            node=i;break;
        }
    }
    mi=INF;sum=0;
    dfs(node,0);
    int sum2=sum;
    getroot(node,0,sum2);//找到另一颗树的重心
    int root2=pos;
    add_edge(root1,root2);
    add_edge(root2,root1);//连接两棵树
    memset(sonmax,0,sizeof(sonmax));
    memset(sonnum,0,sizeof(sonnum));
    solve(1,0);//求路径和
    printf("%lld\n",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/caijiaming/p/11562250.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值