2021寒假程序设计训练----2021/01/02

医院设置

题目描述

设有一颗二叉树如图:
在这里插入图片描述
其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 1。如上图中,若医院建在1 处,则距离和 = 4 + 12 + 2 × 20 + 2 × 20 = 136 4+12+2 \times 20+2\times20=136 4+12+2×20+2×20=136;若医院建在 3 处,则距离和 = 4 × 2 + 13 + 20 + 40 = 81 4×2+13+20+40=81 4×2+13+20+40=81

输入格式

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

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

输出格式

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

输入样例

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

输出样例

81

思路

对每个点做一次BFS即可,记得每次都要初始化d数组,求最小值即可

#include <bits/stdc++.h>
using namespace std;
const int N = 110,M = N*2;
int n;
int h[N],idx,w[N];
queue<int>q;
int d[N];
struct Edge {
    int next,to;
}edge[M];

void add(int a,int b) {
    edge[idx].to = b;
    edge[idx].next = h[a];
    h[a] = idx++;
}

int bfs(int x) {
    memset(d,0,sizeof d);
    int ans = 0;
    q.push(x);
    while(q.size()) {
        int t = q.front();
        q.pop();
        for (int i = h[t]; ~i; i = edge[i].next) {
            int j = edge[i].to;
            if(d[j]||j==x) continue;
            d[j] = d[t]+1;
            //cout<<"编号为:"<<j<<endl;
            ans += d[j]*w[j];
            q.push(j);
        }
    }
    return ans;
}

int main() {
    memset(h,-1,sizeof h);
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        int l,r;
        cin >> w[i] >> l >> r;
        if(l) add(i,l),add(l,i);
        if(r) add(i,r),add(r,i);
    }
    
    int res = 0x3f3f3f3f;
    for (int i = 1; i <= n; i ++) {
        res = min(res,bfs(i));
    }
    cout << res << endl;
    return 0;
}

膜拜

题目描述

神牛有很多…当然…每个同学都有自己衷心膜拜的神牛.

某学校有两位神牛,神牛甲和神牛乙。新入学的 n n n 位同学们早已耳闻他们的神话。

所以,已经衷心地膜拜其中一位了。现在,老师要给他们分机房。但是,要么保证整个机房都是同一位神牛的膜拜者,或者两个神牛的膜拜者人数差不超过 m m m。另外,现在 n n n 位同学排成一排,老师只会把连续一段的同学分进一个机房。老师想知道,至少需要多少个机房。

输入格式

输入文件第一行包含两个整数 n n n m m m

2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行一个非 1 1 1 2 2 2 的整数,第 ( i + 1 ) (i + 1) (i+1) 行的整数表示第 i i i 个同学崇拜的对象, 1 1 1 表示甲, 2 2 2 表示乙。

输出格式

输出一个整数,表示最小需要机房的数量。

输入样例

5 1
2
2
1
2
2

输出样例

2

思路

把2看成-1,题目就可以变成将序列最少分为多少段,使每段和的绝对值 ≤ m ≤m m,求和可以用前缀和,然后就是线性DP了。

时间复杂度 O ( n 2 ) O(n^2) O(n2)

#include <bits/stdc++.h>
using namespace std;
const int N = 2510;

int dp[N],sum[N];

int main() {
    int n,m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        int x;
        cin >> x;
        if(x == 1) sum[i] = sum[i-1]+1;
        else sum[i] = sum[i-1]-1;
    }
    
    memset(dp+1,0x3f,sizeof dp);
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= i; j ++) {
            if(abs(sum[i]-sum[j-1])==i-j+1||abs(sum[i]-sum[j-1])<=m)
            dp[i] = min(dp[i],dp[j-1]+1);
        }
    }
    
    cout << dp[n] << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值