0
点赞
收藏
分享

微信扫一扫

图论题目

一点读书 2022-02-10 阅读 25

题目描述

有一个村庄居住着 nn 个村民,有 n-1n−1 条路径使得这 nn 个村民的家联通,每条路径的长度都为 11。现在村长希望在某个村民家中召开一场会议,村长希望所有村民到会议地点的距离之和最小,那么村长应该要把会议地点设置在哪个村民的家中,并且这个距离总和最小是多少?若有多个节点都满足条件,则选择节点编号最小的那个点。

输入格式

第一行,一个数 nn,表示有 nn 个村民。

接下来 n-1n−1 行,每行两个数字 aa 和 bb,表示村民 aa 的家和村民 bb 的家之间存在一条路径。

输出格式

一行输出两个数字 xx 和 yy。

xx 表示村长将会在哪个村民家中举办会议。

yy 表示距离之和的最小值。

输入输出样例

输入 #1复制

4
1 2 
2 3 
3 4 

输出 #1复制

2 4

说明/提示

数据范围

对于 70\%70% 数据 n \le 10^3n≤103。

对于 100\%100% 数据 n \le 5 \times 10^4n≤5×104。

找树的中心。

法一,用Floyd 时间复杂度O(n*n),代码略;

法二,dp;

#include<iostream>
#include<cstring>
using namespace std;
#define int long long
const int maxn=5e4+5;
const int INF=1e9+5;
int f[maxn],s[maxn],head[maxn<<1];
struct node{
    int to,next;
}edge[maxn<<1];
int cnt=0;int ans=INF,now;
void add_edge(int from,int to)
{
    cnt++;
    edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
void dfs1(int root,int fa,int dep)
{
    s[root]=1;
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to!=fa)
        {
            dfs1(to,root,dep+1);
            s[root]+=s[to];
        }
    }
    f[1]+=dep;
}
void dfs2(int root,int fa)
{
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to!=fa)
        {
            f[to]=f[root]+s[1]-2*s[to];
            dfs2(to,root);
        }
    }
    ans=min(ans,f[root]);
}
signed main()
{
    int n;cin>>n;
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++)
    {
        int from,to;
        cin>>from>>to;
        add_edge(from,to);
        add_edge(to,from);
    }
    dfs1(1,1,0);
    dfs2(1,1);
   for(int i=1;i<=n;i++)
   {
       if(f[i]==ans)
       {
           cout<<i<<" "<<ans<<endl;
           return 0;
       }
   }
}

题目描述

设有一棵二叉树,如图:

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 11。如上图中,若医院建在1 处,则距离和 =4+12+2\times20+2\times40=136=4+12+2×20+2×40=136;若医院建在 33 处,则距离和 =4\times2+13+20+40=81=4×2+13+20+40=81。

输入格式

第一行一个整数 nn,表示树的结点数。

接下来的 nn 行每行描述了一个结点的状况,包含三个整数 w, u, vw,u,v,其中 ww 为居民人口数,uu 为左链接(为 00 表示无链接),vv 为右链接(为 00 表示无链接)。

输出格式

一个整数,表示最小距离和。

输入输出样例

输入 #1复制

5						
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0

输出 #1复制

81

说明/提示

数据规模与约定

对于 100\%100% 的数据,保证 1 \leq n \leq 1001≤n≤100,0 \leq u, v \leq n0≤u,v≤n,1 \leq w \leq 10^51≤w≤105。

树的中心题目同上;

#include<iostream>
#include<cstring>
using namespace std;
#define int long long
const int maxn=1e4+5;
const int INF=1e9+5;
int f[maxn],s[maxn],val[maxn];
int head[maxn];
struct node{
    int to,next;
}edge[maxn];
int cnt=0;int ans=INF;
void add_edge(int from,int to)
{
    cnt++;
    edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt;
}
void dfs1(int root,int fa,int dep)
{
    s[root]=val[root];
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to!=fa)
        {
            dfs1(to,root,dep+1);
            s[root]+=s[to];
        }
    }
    f[1]+=val[root]*dep;
}
void dfs2(int root,int fa)
{
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to!=fa)
        {
            f[to]=f[root]+s[1]-2*s[to];
            dfs2(to,root);
        }
    }
     ans=min(ans,f[root]);
}
signed main()
{
    int n;cin>>n;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        cin>>val[i];
        int a1,a2;cin>>a1>>a2;
        if(a1){
            add_edge(i,a1);
            add_edge(a1,i);
        }
        if(a2)
        {
            add_edge(i,a2);
            add_edge(a2,i);
        }
    }
    dfs1(1,0,0);
    dfs2(1,0);
    cout<<ans<<endl;

举报

相关推荐

0 条评论