医院设置

题目描述
设有一棵二叉树,如图:

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为1。如上图中,
若医院建在1 处,则距离和=4+12+2*20+2*40=136;若医院建在3 处,则距离和=4*2+13+20+40=81……
输入输出格式
输入格式:
第一行一个整数n,表示树的结点数。(n≤100)
接下来的n行每行描述了一个结点的状况,包含三个整数,整数之间用空格(一个或多个)分隔,其中:第一个数为居民人口数;第二个数为左链接,为0表示无链接;第三个数为右链接。
输出格式:
一个整数,表示最小距离和。
输入输出样例
输入样例#1:
5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0
输出样例#1:
81

解:

此题暴力枚举在哪个点设置医院,然后以那个点为根进行DFS即可,

复杂度O(n^2)

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define DB double
 4 using namespace std;
 5 const int N=1e6+10;
 6 struct node{
 7     int u,v,ne;
 8 }e[N];
 9 int h[N],tot,a[N],n;
10 void add(int u,int v)
11 {
12     tot++;e[tot]=(node){u,v,h[u]};h[u]=tot;
13 }
14 ll ans,tmp;
15 void dfs(int u,int fa,int d)
16 {
17     tmp+=1ll*a[u]*d;
18     for(int i=h[u],rr;i;i=e[i].ne)
19     {
20         rr=e[i].v;
21         if(rr!=fa) dfs(rr,u,d+1);
22     }
23 }
24 int main()
25 {
26     scanf("%d",&n);
27     for(int i=1,l,r;i<=n;++i)
28     {
29         scanf("%d",&a[i]);
30         scanf("%d%d",&l,&r);
31         if(l) add(i,l),add(l,i);
32         if(r) add(i,r),add(r,i);
33     }
34     ans=1e12;
35     for(int i=1;i<=n;++i)
36     {
37         tmp=0;
38         dfs(i,0,0);
39         ans=min(ans,tmp);
40     }
41     printf("%lld",ans);
42     fclose(stdin);fclose(stdout);
43     return 0;
44 } 
暴力

也可以用树形DP来写,复杂度O(n)

ok[i]表示以i为根的最优答案,首先我们预处理出ok[1]

sz[i]表示i这棵子树的大小(节点数目之和)

对于( u -> v ) 已知ok[u]

我们只需要减去sz[v],加上除了sz[v]以外的节点数目

即ok[v]=ok[u]-sz[v]+sz[1]-sz[v]=ok[u]+sz[1]-2*sz[v]

得解。

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define DB double
 4 using namespace std;
 5 const int N=1e4+10;
 6 struct node{
 7     int u,v,ne;
 8 }e[N];
 9 int h[N],tot,a[N],n,sz[N];
10 void add(int u,int v)
11 {
12     tot++;e[tot]=(node){u,v,h[u]};h[u]=tot;
13 }
14 ll ans,tmp,ok[N];
15 void dfs1(int u,int fa,int d)
16 {
17     ans+=1ll*a[u]*d;
18     for(int i=h[u],rr;i;i=e[i].ne)
19     {
20         rr=e[i].v;
21         if(rr!=fa) dfs1(rr,u,d+1),sz[u]+=sz[rr];
22     }
23 }
24 void dfs2(int u,int fa)
25 {
26     ans=min(ans,ok[u]);
27     for(int i=h[u],rr;i;i=e[i].ne)
28     {
29         rr=e[i].v;
30         if(rr!=fa) 
31         {
32             ok[rr]=ok[u]+sz[1]-2*sz[rr];
33             dfs2(rr,u);
34         }
35     }
36 }
37 int main()
38 {
39     scanf("%d",&n);
40     for(int i=1,l,r;i<=n;++i)
41     {
42         scanf("%d",&a[i]);sz[i]=a[i];
43         scanf("%d%d",&l,&r);
44         if(l) add(i,l),add(l,i);
45         if(r) add(i,r),add(r,i);
46     }
47     dfs1(1,0,0);ok[1]=ans;
48     dfs2(1,0); 
49     printf("%lld",ans);
50     fclose(stdin);fclose(stdout);
51     return 0;
52 } 
树形DP
原文地址:https://www.cnblogs.com/adelalove/p/8848791.html