Week6作业

A - 氪金带东

问题描述
实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。
在这里插入图片描述Input
输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。

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

Sample Input

5
1 1
2 1
3 1
1 1

Sample Output

3
2
3
4
4

解题思路

  • 树的直径即为树中最远节点的距离
  • 树中任意一点到其他节点的最远距离即为该点到直径两端点之一的距离
  • 所以求某节点到其他节点的最大最大距离,需先求出树直径的端点,再求该点到两端点的距离,取最大。
  • 求直径:任取一点,dfs,记录到达所有叶节点的长度和点(每往下一层,长度等于原长度+当前边长度),长度最大值的点即为一个端点;再从该端点遍历,找到的点为另一个端点。
  • 从两个端点分别往另一侧遍历,记录到达每个点的距离,取较大的输出即可(本题使得每个点只能到达一次)。
  • 用 Node结构体存储点和边长度,用vector <vector< Node > > e二维数组存边,e[i][j]表示与i节点相邻的第j个节点的信息(值、边权)

完整代码

//先找直径的端点
//从两端点遍历要到达的点,得到最远路径
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int v1,v2,v;//直径的端点
int N;
int Max=0;

int llength[10001];

struct Node 
{ 
	int n;
	int length;
};



vector <vector< Node > > e;//二维数组,e[i][j]表示与i节点 相邻的第j个节点 


//找从a开始最大路的点 
void findv(int a,int b,int Length=0)
{ 
	if(e[a].size()==1)
	if(Length>Max) v = a,Max = Length;
	for(int i = 0;i<e[a].size();i++)
	{    
		if(e[a][i].n!=b)
		findv(e[a][i].n,a,e[a][i].length+Length);
	}
}


void maxlength(int a,int be,int Length=0)
{
	
	if(Length>llength[a])
	{llength[a]=Length;} 
	for(int i=0;i<e[a].size();i++)
			if(e[a][i].n!=be)
				{ 
				 maxlength(e[a][i].n,a,Length+e[a][i].length);
				}



}



int main()
{
	while(scanf("%d",&N)!=-1)
{		memset(llength,0,sizeof(llength));
		e.clear();
		e.resize(N+10);
	for(int i=2;i<=N;i++)
	{
		int a,b;
		scanf("%d %d",&a,&b);
		Node nod;
		nod.n=a;
		nod.length=b;
		e[i].push_back(nod);
		Node nodd;
		nodd.n = i;
		nodd.length = b;
		e[a].push_back(nodd);
		}
		Max=0; 
		findv(1,0);
		v1=v;
		Max=0;
		findv(v1,0);
		v2=v;
		
		maxlength(v1,0);
		maxlength(v2,0);
		for(int l=1;l<=N;l++)
		printf("%d\n",llength[l]);
	}
} 

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

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

Sample 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 

Sample Output

4
1
1

解题思路
本题为简单的并查集问题

  • 用parent数组表示每个节点的祖先,起初每个节点的祖先都是自己,即parent[i]=i
  • 对每个集合,每输入一个元素合并一个,如果有已知集合的元素 ,则会根据parent的值合并
  • a与b合并时,先找到a、b最“往上”的祖先,判断是否相等。是则不合并,不是则把其中一个的parent置为另一个,另一个祖先下节点的数目=自身数目+新合并节点祖先下的数目
  • 找到0的祖先,输出它的节点数目即可

完整代码


#include<iostream>
using namespace std;
int n,m,num;
int parent[30010],number[30010];

void unite(int a,int b)
{//找最原始的parent
	
	while(parent[a]!=a)
		a=parent[a];
	while(parent[b]!=b)
		b=parent[b];
	if(a!=b)//不属于一个则合并 
{	//b的parent改为a 
	parent[b]=a;  
	number[a]=number[a]+number[b];
	 } 


}
int main()
{
	while(cin>>n>>m)
	{
	for(int i=0;i<n;i++)
		parent[i]=i,number[i]=1;//起初每个人的代表都是自己,个数都是1个 
	if(n==0&&m==0)
		break;
	for(int i=0;i<m;i++)
	{	cin>>num;
		int element1,element2;
		for(int l=0;l<num;l++)
		{	cin>>element2;
			if(l==0)
			{element1=element2;continue;}
			unite(element1,element2);
			element1=element2;
		
		}	}
		int x=0;
		while(parent[x]!=x)
			x=parent[x];
		cout<<number[x]<<endl;
		}


}

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

Output

9

解题思路

  • 本题可转化为最小生成树问题,每次选的方式都是增加一块被灌溉的田,所以每次选消耗最小的方式即可。
  • 类似Kruskal算法,先将所有黄河之水天上来的消耗排序,每次取最小的,判断一下对应的田是否已被灌溉,再找从已被灌溉的田中使用传送门消耗mp的最小值,选较小的实施,直到所有田都被灌溉。
  • 用reach数组表示田的灌溉情况,结构体、二维矩阵分别储存两种灌溉方法消耗的mp。

完整代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
struct W
{
	int number;
	int weight;
};


W w[302];
int reach[302];
W node[302];
int p[302][302];
int count1=0;
int count2=0; 
int mp=0;  
void find()//从黄河之水天上来和传送门方法里找最小的 
{	while(count2<n)
{	int a=-1;
	int b=-1;
	while(reach[w[count1].number]==1)
		count1++;
	int min=w[count1].weight;//首选黄河之水天上来 
//	cout<<"weight"<<w[count1].weight<<" i "<<w[count1].number<<endl;
	for(int i=0;i<count2;i++)//看所有的已知点有没有传送门耗蓝更少 
		for(int l=0;l<n;l++)
			if(p[node[i].number][l]<min)
				{
				if(reach[l]==0)//加入不会成环 
			{	a=node[i].number;b=l;
				min=p[a][b];
			}	}
	if(a!=-1)//传送门
	{node[count2].number=b;
	count2++;
	reach[b]=1;
	} 
	else
	{
	node[count2].number=w[count1].number;
	reach[w[count1].number]=1;
	count1++;
	count2++;
	
	}
//	cout<<"a"<<a<<" "<<"b"<<b<<endl;
	mp=mp+min;}
}

bool compare(W a,W b)
{
	return a.weight<b.weight;

}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{	w[i].number=i;cin>>w[i].weight;}
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			cin>>p[i][j];
	
	memset(reach,0,sizeof(reach));
	sort(w,w+n,compare);
	find();
	cout<<mp<<endl;


} 

D - 数据中心
在这里插入图片描述
Example
Input

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

Output

4

解题思路

  • 要找的T(max)即为每层的Tm的max,而每层的Tm即为每层边权最大的边,即T(max)=最大边。
  • 本题可简化为使最大边最小,即找最小生成树即可。
  • 采用kruskal算法构建最小生成树,用并查集保证不成环。
  • 将所有的边按权值排序,每次取最小边,将两个节点合并(判断祖先是否一致,是则加入会成环,不合并,跳过。否则合并),记录最大值,最后输出即可。
  • 结构体存边(u,v,w),parent数组表示每个点的祖先(初始化parent[i]=i)

完整代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct Edge
{
	int begin;
	int end;
	int length;
};

Edge e[100010];
int parent[50010];
int n,m; 
bool compare(Edge a,Edge b){return a.length<b.length;}
int find(int x)
{ 	return parent[x]==x?x:parent[x]=find(parent[x]);
}
bool unite(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
		return false;
	parent[x]=y;
	return true;
} 
int mintree()
{	sort(e,e+m,compare); 
	int Max=0; 
	for(int i=0;i<m;i++)
{	if(unite(e[i].begin,e[i].end))//两个点都到过了
		if(e[i].length>Max)
			Max=e[i].length;		
			
}	return Max;}
	
 

int main()
{
	cin>>n>>m;
	int root;
	cin>>root;
	for(int i=0;i<m;i++)
		cin>>e[i].begin>>e[i].end>>e[i].length;
	
	for(int i=0;i<n;i++)
		parent[i]=i;	
	cout<<mintree()<<endl;



}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值