zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    js原生实现div渐入渐出
    js刷新界面前事件onbeforeunload
    js手机短信验证
    scroll滚动条样式修改
    省市区三级联动
    js this的含义以及讲解
    炫酷实用的CSS3代码垂直手风琴菜单
    机器学习初探(手写数字识别)HOG图片
    机器学习初探(手写数字识别)matlab读取数据集
    Google B4网络阅读记录(翻译)
  • 原文地址:https://www.cnblogs.com/caijiaming/p/11562250.html
Copyright © 2011-2022 走看看