Week6 作业

A - 氪金带东

实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。
在这里插入图片描述
提示: 样例输入对应这个图,从这个图中你可以看出,距离1号电脑最远的电脑是4号电脑,他们之间的距离是3。 4号电脑与5号电脑都是距离2号电脑最远的点,故其答案是2。5号电脑距离3号电脑最远,故对于3号电脑来说它的答案是3。同样的我们可以计算出4号电脑和5号电脑的答案是4.

Input

输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。

Output

对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N).

Example Input

5
1 1
2 1
3 1
1 1

Example Output

3
2
3
4
4

题意:
有若干台电脑通过长度不同的网线相连,对于每一台电脑,计算出与其相连的所有电脑中二者之间最长的网线长度。

分析:
首先应该找出树的直径,假设直径两端的点为v1、v2,则对于任意一个点,到其他点的最大长度就是是到点v1或v2的长度。
所以首要任务求出树的直径。对于如何求树的直径,有如下定理:
从任意一个点遍历整棵树,寻找与它距离最远的一片叶子,这个叶子一定是树的直径的一个端点。利用这个方法,连续进行两次dfs,就可以求出树的直径,即找到了点v1、v2。
对于任意一个点,当找到v1、v2后,再进行一次dfs,所求的最大距离就是改点到v1的距离和到v2的距离中的最大值。

代码如下:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

struct edge 
{
	int to;
	int w;
};

vector<edge> graph[10010];
int ans[10010];
int length, s;

void dfs(int u, int f, int len)
{
	if (length <= len) 
	{
		s = u;
		length = len;
	}
	for (int i = 0; i < graph[u].size(); i++)
	{
		int v = graph[u][i].to;
		if (v == f)
			continue;
		dfs(v, u, len + graph[u][i].w);
		ans[v] = max(ans[v], len + graph[u][i].w);
	}
}

int main() 
{
	int n;
	edge e;
	while (cin >> n) 
	{
		for (int i = 0; i <= n; i++) 
			graph[i].clear();
		for (int i = 2; i <= n; i++) 
		{
			int a, b;
			cin >> a >> b;
			e.to = a;
			e.w = b;
			graph[i].push_back(e);
			e.to = i;
			graph[a].push_back(e);
		}
		memset(ans, 0, sizeof(ans));
		length = 0;
		s = 0;
		dfs(1, -1, 0);
		dfs(s, -1, 0);
		dfs(s, -1, 0);
		for (int i = 1; i <= n; i++)
			cout << ans[i] << endl;
	}
	return 0;
}

B - 戴好口罩!

新型冠状病毒肺炎(Corona Virus Disease 2019,COVID-19),简称“新冠肺炎”,是指2019新型冠状病毒感染导致的肺炎。
如果一个感染者走入一个群体,那么这个群体需要被隔离!
小A同学被确诊为新冠感染,并且没有戴口罩!!!!!!
危!!!
时间紧迫!!!!
需要尽快找到所有和小A同学直接或者间接接触过的同学,将他们隔离,防止更大范围的扩散。
众所周知,学生的交际可能是分小团体的,一位学生可能同时参与多个小团体内。
请你编写程序解决!戴口罩!!

Input

多组数据,对于每组测试数据:
第一行为两个整数n和m(n = m = 0表示输入结束,不需要处理),n是学生的数量,m是学生群体的数量。0 < n <= 3e4 , 0 <= m <= 5e2
学生编号为0~n-1
小A编号为0
随后,m行,每行有一个整数num即小团体人员数量。随后有num个整数代表这个小团体的学生。

Output

输出要隔离的人数,每组数据的答案输出占一行

Example Input

100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0

Example Output

4
1
1

题意:
有一名同学被确诊,同学之间通过小团体接触,输出需要隔离的同学。

分析:
本题主要使用并查集。
通过函数init、find、unite实现并查集的初始化、查询和合并功能。
将每个群体中的学生合并在同一个并查集中,只需要查询0号学生所在的并查集中共有多少人。

代码如下:

#include<iostream>
#include<cstdio>
using namespace std;

int n, m;
int uni[30010];
int dis[30010];

void init() 
{
	for (int i = 0; i < n; i++)
	{
		uni[i] = i;
		dis[i] = 1;
	}
}

int find(int x)
{
	if (uni[x] == x)
		return x;
	else
		return uni[x] = find(uni[x]);
}

void unite(int a, int b)
{
	int x = find(a), y = find(b);
	if (x == y)
		return;
	if (dis[x] > dis[y])
		swap(x, y);
	uni[x] = y;
	dis[y] += dis[x];
}

int main()
{
	while (scanf("%d%d", &n, &m))
	{
		if (n == 0 && m == 0) 
			break;
		init();
		int a, b, c;
		for (int i = 0; i < m; i++)
		{
			scanf("%d%d", &a, &b);
			a -= 1;
			while (a--)
			{
				cin >> c;
				unite(b, c);
			}
		}
		printf("%d\n", dis[find(0)]);
	}
	return 0;
}

C - 掌握魔法の东东 I

东东在老家农村无聊,想种田。农田有 n 块,编号从 1~n。种田要灌氵
众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (1<=n<=3e2)
黄河之水天上来的消耗是 Wi,i 是农田编号 (1<=Wi<=1e5)
建立传送门的消耗是 Pij,i、j 是农田编号 (1<= Pij <=1e5, Pij = Pji, Pii =0)
东东为所有的田灌氵的最小消耗

Input

第1行:一个数n
第2行到第n+1行:数wi
第n+2行到第2n+1行:矩阵即pij矩阵

Output

东东最小消耗的MP值

Example Input

4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0

Example Output

9

题意:
要对一块田地上的若干地块进行灌溉,有两种灌溉方法,一种是直接往这一块地浇水,第二种是从旁边的地块引流,每个操作都有不同的损耗,要灌溉所有地块,求出最小的损耗。

分析:
本题核心算法仍然是并查集,但最主要考虑如何调用并查集调用并查集。
本题的灌溉方法有两种,但可以归结为一种,全部看成连通引水。将数据升序排序后利用find函数,每次检查两个最小成本点是否都连通,若没有则利用unite函数进行合并,并将成本加入结果。当所有点全部连通,输出结果。

代码如下:

#include<iostream>
#include<algorithm>
using namespace std;

struct edge
{
	int u;
	int v;
	int w;
	edge(int U = 0, int V = 0, int W = 0) :u(U), v(V), w(W) {}
	edge(const edge& a) :u(a.u), v(a.v), w(a.w) {}
};

int cmp(edge& a, edge& b)
{
	return a.w < b.w;
}

edge e[100010];
int uni[100010] = { 0 };
int dis[100010] = { 0 };
int n, num = 0, ans = 0;

void init()
{
	for (int i = 0; i <= n; i++)
	{
		uni[i] = i;
		dis[i] = 1;
	}
}

int find(int x)
{
	if (x == uni[x])
		return x;
	else 
		return uni[x] = find(uni[x]);
}

bool unite(int x, int y)
{
	int a = find(x);
	int b = find(y);
	if (a == b)
		return false;
	else if (dis[a] < dis[b])
	{
		dis[b] += dis[a];
		uni[a] = b;
	}
	else
	{
		dis[a] += dis[b];
		uni[b] = a;
	}
	return true;
}

int main()
{
	cin >> n;
	init();
	for (int i = 1; i < n + 1; i++)
	{
		int m;
		cin >> m;
		e[num++] = edge(0, i, m);
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			int mp;
			cin >> mp;
			if (mp == 0)
				continue;
			e[num++] = edge(i, j, mp);
		}
	}
	sort(e, e + num, cmp);
	for (int i = 0; i < num; i++)
	{
		int u = e[i].u;
		int v = e[i].v;
		int m = e[i].w;
		if (unite(u, v))
			ans += m;
	}
	cout << ans;
}

D - 数据中心

在这里插入图片描述

Example Input

4
5
1
1 2 3
1 3 4
1 4 5
2 3 8
3 4 2

Example Output

4

Notes

在这里插入图片描述

题意:
有一个无向图,图中有一个根节点,每两个节点之间传输信息都需要一定的时间,现在每个节点都要向根节点传输一条信息,求出最短用时。

分析:
说到底,这道题的最终要求是先求出该图的最小生成树,然后以root为根节点每一层向下遍历即可。
先将给出的数据从小到大排序,然后开始建树,使用数组标记是否到达过某一个点,这里使用了kruskal算法。
从根节点开始层次遍历,定义变量将权重相加,最后结果输出。

代码如下:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

struct edge 
{
    int start;
    int to;
    int val;
};

edge e[500000];
int father[100000];
int n, m, u, v, total;
int ans = 0;

int find(int x) 
{
    if (father[x] == x)
        return x;
    else
        return father[x] = find(father[x]);
}

int cmp(edge a, edge b) 
{
    return a.val < b.val;
}

void kruskal() 
{
    long long num = 0;
    for (int i = 1; i <= m; i++) 
    {
        u = find(e[i].start);
        v = find(e[i].to);
        if (u == v) 
            continue;
        num += e[i].val;
        ans = max(ans, e[i].val);
        father[u] = v;
        total++;
        if (total == n - 1) 
            break;
    }
}

int main() 
{
    cin >> n >> m;
    int root;
    cin >> root;
    for (int i = 1; i <= n; i++) 
        father[i] = i;
    for (int i = 1; i <= m; i++) 
        cin >> e[i].start >> e[i].to >> e[i].val;
    sort(e + 1, e + 1 + m, cmp);
    kruskal();
    cout << ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值