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).

Simple Input:

5
1 1
2 1
3 1
1 1

Simple Output:

3
2
3
4
4

题目分析:
最基础的做法就是,对每一个点进行BFS或者DFS,找出每一个点的最大距离的点,这种做法是很消耗时间的,每一次都需要遍历所有的点,那么时间就是n²的,所以为了减少搜索的时间,可以找出数直径的两个端点,在从端点进行DFS或者BFS将最大距离统计出来,时间是O(n);
代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
int len[100001];
int m1 = 0;
int l1 ;
struct Node{
	int node;
	int length;
};
vector<vector<Node> > G;
void dfs(int x,int last,int l)
{
	if(l>l1) m1 = x,l1 = l;
	if(len[x]<l) len[x] = l; 
	for(int i = 0;i<G[x].size();i++)
	{
		if(G[x][i].node == last) continue;
		dfs(G[x][i].node,x,G[x][i].length+l);
	}
}

int main()
{
	int n;
	while(cin>>n)
	{
		G.clear();
		G.resize(n+5);
		l1 = 0;
	int i = 2;
	while(i<=n)
	{
		int a,b;
		cin>>a>>b;
		Node _node;
		_node.node = a;
		_node.length = b;
		G[i].push_back(_node);
		Node _node2;
		_node2.node = i;
		_node2.length = b;
		G[a].push_back(_node2);
		i++;
	}

	memset(len,0,sizeof(len));
	dfs(1,-1,0);
	dfs(m1,-1,0);
	dfs(m1,-1,0);
	for(int j =1;j<=n;j++) cout<<len[j]<<endl;
}
//	for(int j = 0;j <= n;j++)
//	{
//		cout<<j<<"->";
//		for(vector<Node>::iterator iter = G[j].begin();iter!=G[j].end() ;iter++)
//		{
//			cout<<iter->node<<" "<<iter->length<<"| ";
//		}
//		cout<<endl;
//	}
	return 0;
 } 
// 0->
//1->2 1| 5 1|
//2->1 1| 3 1|
//3->2 1| 4 1|
//4->3 1|
//5->1 1|

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 0

Sample Output:

4
1
1

题目分析:
并查集的板子题,为提高查询速度可以将所有节点挂在一个节点之下
记得在每次用完之后要清空vector
代码如下:

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

const int maxn = 3e4+5;

int par[maxn];
int r[maxn];
void init(int n)
{
	for(int i = 0;i<=n;i++)
	{
		par[i] = i;r[i] = 1;
	}
}
int find(int x)
{
	return par[x]==x ? x : par[x]=find(par[x]);
}

bool unit(int x,int y)
{
	x = find(x);y = find(y);
	if(x==y) return false;
	par[x] = y;
	r[y]+=r[x];
	return true;
}

int main()
{
	int m,n;
	while(~scanf("%d%d",&n,&m))
	{
		if(m==0&&n==0) break;
		init(n);
		while(m--)
		{
			int num;
			scanf("%d",&num);
			int last = -1;
			while(num--)
			{
				int a;
				scanf("%d",&a);
				if(last!=-1) unit(a,last);
				last = a;
			}
		}
		cout<<r[find(0)]<<endl;
	}
}

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

IMPUT;
第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

题目分析;
最小生成树版子题,可以形成最小生成树之后,再加上一个消耗最小的农田灌溉,或者将生成一个超级原点,到所有的农田的距离为到灌溉的距离,直接套用最小生成树
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 3e2+5;
using namespace std;
int par[maxn];
int tot;
int n;
void init(int n){for(int i = 0;i<=n;i++) par[i] = i;}
int find(int x){return par[x]==x? x:par[x] = find(par[x]);}
struct Edge{
	int u,v,len;
	bool operator<(const Edge& b)
	{
		return len < b.len;
	}
}Es[maxn*maxn];

 int krukal()
 {
 	init(n);
 	sort(Es,Es+tot);
 	int cnt = 0,ans = 0;
 	int x,y;
 	for(int i = 0;i<tot&&cnt<=n;i++)
 	{
 		x = find(Es[i].u),y=find(Es[i].v);
 		if(x!=y)
		 {
 			ans+=Es[i].len;
 			cnt++;
 			par[x] = y;
		 }
	 }
	 return ans;
 	
 }
int main()
{
	cin>>n;
	tot=0;
	for(int i =1;i<=n;i++) cin>>Es[tot].len,Es[tot].u=0,Es[tot].v=i,tot++;
	for(int i = 1;i<=n;i++)
	{
		for(int j = 1;j<=n;j++)
		{	
			cin>>Es[tot].len;
			if(j<i)
			{
		
			Es[tot].u = i;
			Es[tot].v=j;
			tot++;
			}
		}
	}
	cout<<krukal();
	
}

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

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

Sample Output;

4

题目分析:
此题只是题目较长,在观察样例之后,发现人root这个点没有多少用处,就是一个最小生成树问题

代码如下:

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
const int maxn =1e5;
int par[maxn];

int cnt = 1;
void init()
{
	for(int i = 0;i<maxn;i++) par[i] = i;
}

int find(int x)
{
	return par[x]==x? x:par[x] = find(par[x]);
}
//bool unit(int x,int y)
//{
//	x = find(x),y = find(y);
//	if(x==y) return false;
//	par[x] = y;
//	return true;
//}
struct Edge{
	int u,v,len;
	Edge(int f,int t,int l):u(f),v(t),len(l){
	}
	Edge()
	{
		
	}
	bool operator<(const Edge& b)
	{
		return len < b.len;
	}
};
Edge edge[100010];



int main()
{
	int m,n ,root;
	cin>>n>>m>>root;
	for(int i = 1,u,v,t;i<=m;i++)
	{
		cin>>u>>v>>t;
		edge[cnt].u = u;
		edge[cnt].v = v;
		edge[cnt++].len = t;
	}
	sort(edge+1,edge+m+1);
	init();
	int ans = -1;
	for(int i = 1,temp = 0;temp!=n-1;i++)
	{
		int x = find(edge[i].u);int y = find(edge[i].v);
		if(x!=y)
		{
			par[x] = y;
			temp++;
			ans = edge[i].len;
		}
	}
	cout<<ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值