P1364 医院设置

P1364 医院设置

题目描述

设有一棵二叉树,如图:

                                         

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为l。如上图中,

若医院建在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

 

分析和解答:

1、暴力

医院建的位置就是root点

数据结构是一个双向图

代价=步长*人数

时间复杂度:O(n*n)

 

 1 #include <bits/stdc++.h>
 2 const int N=1e2+10;
 3 const int INFINITE=1<<30;
 4 using namespace std;
 5 vector<int> vct[N];
 6 int val[N],n,ans=INFINITE;
 7 bool vis[N];
 8 
 9 void init(){
10     cin>>n;
11     int w,l,r;
12     for(int i=1;i<=n;i++){
13         cin>>w>>l>>r;
14         val[i]=w;
15         if(l){
16             vct[i].push_back(l);
17             vct[l].push_back(i);
18         }
19         if(r){
20             vct[i].push_back(r);
21             vct[r].push_back(i);
22         }
23     }
24 }
25 
26 int find(int r,int step){
27     if(vis[r]) return 0;
28     vis[r]=true;
29     int ans=val[r]*step;
30     for(int i=0;i<vct[r].size();i++){
31         int v=vct[r][i];
32         ans+=find(v,step+1);
33     }
34     return ans;
35 }
36 
37 void search(){
38     for(int i=1;i<=n;i++){
39         memset(vis,false,sizeof(vis));
40         int tmp=find(i,0);
41         if(tmp<ans) ans=tmp; 
42     }
43 } 
44 
45 
46 int main(){
47     //freopen("in.txt","r",stdin);
48     init();
49     search();
50     cout<<ans<<endl;
51     return 0;
52 } 

2、最短路解法

spfa解法

求出医院的那个点到其它点的距离

时间复杂度:O(n*2e+n*n) e大概等于2n

 

 只列出了最短路里面的一种解法,当然也可以用其它最短路来做

 1 #include <bits/stdc++.h>
 2 const int N=1e2+10;
 3 const int INFINITE=1<<30;
 4 using namespace std;
 5 vector<int> vct[N];
 6 int val[N],n,ans=INFINITE,dis[N];
 7 bool vis[N];
 8 queue<int> q;
 9 
10 void init(){
11     cin>>n;
12     int w,l,r;
13     for(int i=1;i<=n;i++){
14         cin>>w>>l>>r;
15         val[i]=w;
16         if(l){
17             vct[i].push_back(l);
18             vct[l].push_back(i);
19         }
20         if(r){
21             vct[i].push_back(r);
22             vct[r].push_back(i);
23         }
24     }
25 }
26 
27 void spfa(int s){
28     dis[s]=0;
29     q.push(s);
30     vis[s]=true; 
31     while(!q.empty()){
32         int u=q.front();q.pop();
33         vis[u]=false;
34         for(int i=0;i<vct[u].size();i++){
35             int v=vct[u][i];
36             if(dis[v]>dis[u]+1){
37                 dis[v]=dis[u]+1;
38                 if(!vis[v]){
39                     q.push(v);
40                     vis[v]=true;    
41                 } 
42             }
43         }
44     }
45 }
46 
47 void search(){
48     for(int i=1;i<=n;i++){
49         memset(vis,false,sizeof(vis));
50         memset(dis,0x3f,sizeof(dis));
51         spfa(i);
52         int tmp=0;
53         for(int i=1;i<=n;i++){
54             tmp+=dis[i]*val[i];
55         }
56         if(tmp<ans) ans=tmp; 
57     }
58 } 
59 
60 
61 int main(){
62     //freopen("in.txt","r",stdin);
63     init();
64     search();
65     cout<<ans<<endl;
66     return 0;
67 } 

3、树形dp解法

dp[i]表示以i为根的子树的最优值。

v是i的孩子

dp[i] =dp[v]+i的孩子和

时间复杂度:O(n*n)

 

 1 #include <bits/stdc++.h>
 2 const int N=1e2+10;
 3 const int INFINITE=1<<30;
 4 using namespace std;
 5 vector<int> vct[N];
 6 int val[N],n,ans=INFINITE,dp[N];
 7 bool vis[N];
 8 
 9 void init(){
10     cin>>n;
11     int w,l,r;
12     for(int i=1;i<=n;i++){
13         cin>>w>>l>>r;
14         val[i]=w;
15         if(l){
16             vct[i].push_back(l);
17             vct[l].push_back(i);
18         }
19         if(r){
20             vct[i].push_back(r);
21             vct[r].push_back(i);
22         }
23     }
24 }
25 
26 int dfs(int r){
27     if(vis[r]) return 0;
28     vis[r]=true;
29     int sum=0;
30     for(int i=0;i<vct[r].size();i++){
31         int v=vct[r][i];
32         if(!vis[v]){
33             sum+=(val[v]+dfs(v)); 
34             dp[r]+=dp[v];
35         } 
36     }
37     dp[r]+=sum;
38     return sum;
39 }
40 
41 void search(){
42     for(int i=1;i<=n;i++){
43         memset(vis,false,sizeof(vis));
44         memset(dp,0,sizeof(dp));
45         dfs(i);
46         if(dp[i]<ans) ans=dp[i]; 
47     }
48 } 
49 
50 
51 int main(){
52     //freopen("in.txt","r",stdin);
53     init();
54     search();
55     cout<<ans<<endl;
56     return 0;
57 } 
 
 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/Renyi-Fan/p/7594025.html