信息学奥赛一本通评测系统P1338【例3-3】医院设置

        恭喜你看到了这篇题解,他会让你避开很多坑(新手推荐,大佬提些建议嘛)

当然,我不想让大佬像下面这道题中大佬一样。[AHOI2017/HNOI2017]大佬 - 洛谷https://www.luogu.com.cn/problem/P3724

                

                                               1338:【例3-3】医院设置


                                        时间限制: 1000 ms         内存限制: 65536 KB
                                                       提交数: 5111     通过数: 3431

【题目描述】

设有一棵二叉树(如下图),其中圈中的数字表示结点中居民的人口,圈边上数字表示结点编号。现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻结点之间的距离为11。就本图而言,若医院建在11处,则距离和=4+12+2×20+2×40=136=4+12+2×20+2×40=136;若医院建在33处,则距离和=4×2+13+20+40=81=4×2+13+20+40=81……

【输入】

第一行一个整数nn,表示树的结点数(n≤100n≤100)。接下来的nn行每行描述了一个结点的状况,包含三个整数,整数之间用空格(一个或多个)分隔,其中:第一个数为居民人口数;第二个数为左链接,为00表示无链接;第三个数为右链接,为00表示无链接。

【输出】

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

【输入样例】

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

【输出样例】

81

这道题我的第一个思路就是“枚”可是这个东西上上下下,不好枚吧!

也没办法了,先把结构体数组写了:

struct node{
    int father,left,right,data;
}a[10001];

然后我也不知道该怎么办了,再把输入写了吧:

cin>>n;
for(int i=1;i<=n;i++)
	cin>>a[i].data>>a[i].left>>a[i].right;

代码的原型:

#include<bits/stdc++.h>
using namespace std;
struct node{
	int data,father,left,right;
}a[10001];
int n;
int main()
{
	
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i].data>>a[i].left>>a[i].right;
	
    return 0;
}

我们不是创建了father吗,我们就把father定了吧

data134122040
father013131212
left402000
right
1204000

我们需要知道father栏中的数,那么代码遍历之后left和right的father是i

a[a[i].left].father=i;
a[a[i].right].father=i;

代码段:

for(int i=1;i<=n;i++)
{
	a[a[i].left].father=i;
	a[a[i].right].father=i;
}

遍历(枚举):

for(int i=1;i<=n;i++)
{
	memset(v,0,sizeof(v));
	ans=min(f(i,0),ans);
}
cout<<ans<<endl;

f函数找父亲,找左孩子,找右孩子,相加,加路程,return,完美!

int f(int x,int d)
{
	if(x==0||v[x]==1)
		return 0;
	v[x]=1;
	int l=f(a[x].left,d+1);
	int r=f(a[x].right,d+1);
	int t=f(a[x].father,d+1);
	return l+r+t+a[x].data*d;
}

AC代码:

#include<bits/stdc++.h>
using namespace std;
struct node{
	int data,father,left,right;
}a[10001];
int n,ans=INT_MAX,v[10001]={0};
int f(int x,int d)
{
	if(x==0||v[x]==1)
		return 0;
	v[x]=1;
	int l=f(a[x].left,d+1);
	int r=f(a[x].right,d+1);
	int t=f(a[x].father,d+1);
	return l+r+t+a[x].data*d;
}
int main()
{
	
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i].data>>a[i].left>>a[i].right;
	for(int i=1;i<=n;i++)
	{
		a[a[i].left].father=i;
		a[a[i].right].father=i;
	}
	for(int i=1;i<=n;i++)
	{
		memset(v,0,sizeof(v));
		ans=min(f(i,0),ans);
	}
	cout<<ans<<endl;
    return 0;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值