2023.8.10

A.树的结点计数

  • 传统题 1000ms 256MiB

Description

第一行是一个整数N(1≤N ≤50000),表示计算机的台数,计算机被编号为1..N。 下面N-1行,每行包括两个整数X, Y,表示X和Y这两台计算机之间由一条网线连接。 1号点为根

Format

Input

第一行给出数字N

接下来N-1行描述这个树

Output

给出N行,分别表示从1号到N号点,以之为根的子树有多少个点,将结果-1后再输出

Samples

输入数据 1

3
1 2
1 3

输出数据 1

2
0
0

vector二维数组,d[i][j]:节点i的第j个子节点的编号为d[i][j]

递归

#include<bits/stdc++.h>
#define forf(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
vector<int>d[50005]; 
int n,x,y,ans[50005];
void trv(int u,int f)
{
	ans[u]=1;
	forf(i,0,d[u].size()-1)
		if(d[u][i]!=f)
		{
			trv(d[u][i],u);
			ans[u]+=ans[d[u][i]];
		}
}
int main()
{
	scanf("%d",&n);
	forf(i,1,n-1)
	{
		scanf("%d %d",&x,&y);
		d[x].push_back(y);
		d[y].push_back(x);
	}
	trv(1,0);
	forf(i,1,n)
	printf("%d\n",ans[i]-1);
	return 0;	
}

B.树的深度计数

  • 传统题 1000ms 256MiB

Description

Format

Input

第一行是一个整数N(1≤N ≤50000),表示计算机的台数,计算机被编号为1..N。 下面N-1行,每行包括两个整数X, Y,表示X和Y这两台计算机之间由一条网线连接。 1号点为根.

Output

给出N行,分别表示从1号到N号点,每个点的深度为多少

Samples

输入数据 1

3
1 2
1 3

输出数据 1

0
1
1

递归

#include<bits/stdc++.h>
#define forf(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
vector<int>d[50005]; 
bool vis[50005];
int n,x,y,ans[50005];
void dg(int p,int dep,int f)//当前节点,层数,父节点 
{
	ans[p]=dep;
	vis[f]=true;
	forf(i,0,d[p].size()-1)
		if(vis[d[p][i]]==false)
			dg(d[p][i],dep+1,p);
}
int main()
{
	scanf("%d",&n);
	forf(i,1,n-1)
	{
		scanf("%d %d",&x,&y);
		d[x].push_back(y);
		d[y].push_back(x);
	}
	dg(1,0,0);
	forf(i,1,n)
		printf("%d\n",ans[i]);
	return 0;	
}

C.小J逛公园

  • 传统题 1000ms 256MiB

Description

小J来到一个公园,公园中有N个景点,用M条无向边相连.

公园的结构并不是一棵树,而是一个图,也就是说可能任两点之间都有边相连

小J从第1个景点出发,当走到分岔路口的时候,他会选择一个编号最小的景点前去游玩,已走过的景点不再去游玩了,如果相邻的所有景点都走过的话,则回到上一个出发点。直至所有景点都走过并且只走过一次

Format

Input

第一行给出N,M代表景点数与边数

接下来M行,每行两个数字a,b,代表a与b之间有边

N<=100.

M<=N*(N-1)/2

Output

一行输出N个数字,每个数字后面一个空格,代表游玩的过程。

Samples

输入数据 1

5 4
1 2
1 3
2 4
2 5

输出数据 1

1 2 4 5 3

Hint

1:通过本题学会使用vector保存一棵树,或一个图

2:如果树的边,或者图的边,是有边权的,应该如何保存?

可能是图,仅标记父节点可能出现1->2->3->1->2->3...的死循环,所以要开数组标记点是否走过

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y; 
bool vis[111];
vector<int>d[111];
void trv(int p)
{
	printf("%d ",p);
	vis[p]=true;
	for(int i=0;i<=d[p].size()-1;i++)
		if(vis[d[p][i]]==false)
		{
			vis[d[p][i]]=true;
			trv(d[p][i]);
		}	
	return;		
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d",&x,&y);
		d[x].push_back(y);
		d[y].push_back(x);
	}
	for(int i=1;i<=n;i++)
		sort(d[i].begin(),d[i].end());//d[i][1],d[i][2],...,d[i][n]按字典序排序 
	trv(1);
	return 0;
}

D.扫雪系列I

  • 传统题 1000ms 128MiB

说明

大雪履盖了整个城市,市政府要求冬季服务部门尽快将一些街道(列在一份清单中)的积雪清除掉以恢复交通,整个城市由许多交叉路口和街道构成,当然任意两个交叉路口都是直接或间接连通的,清单给出了最少的街道,使得这些街道的积雪清除后任意两个交叉路口之间有且仅有一条通路,冬季服务部门只有一辆铲雪车及一名司机,这辆铲雪车的出发点位于某个交叉路口。 
无论街道上有没有积雪,铲雪车每前进一米都要消耗一升燃料,冬季服务部门要求司机在铲除清单上的所有街道的积雪的前提下,要求消耗燃料最少,积雪铲完后车可以停在任意的交叉路口。

输入格式

输入文件的第一行包含两个整数N和S,1≤N≤100000,1≤S≤N。N为交叉路口的总数;S为铲雪车出发的路口序号。
路口的标号为1••N。 
接下来的N-1行为清单上的街道,每一行包含三个用空格隔开的整数A、B、C,表示一条从交叉路口A到交叉路口B的街道,C为该街道的长度,单位为米,1≤C≤1000。

输出格式

输出文件仅一行包含一个整数表示清除所有积雪所需的最少的燃料数量。

样例

输入数据 1

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

输出数据 1

5

有的路径要走回头路,有的不要,让不走回头路的路径最长即可,故ans=2*sum-num

开结构体保存边权,子节点两个性质

#include<bits/stdc++.h>
#define forf(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,s,x,y,z,sum,ans=INT_MIN;
struct node
{
	int v,len;
};
vector<node>d[100005];
void trv(int p,int num,int f)//当前节点,到出发点的距离,父节点 
{
	ans=max(ans,num);
	forf(i,0,d[p].size()-1)
		if(d[p][i].len!=f)
			trv(d[p][i].len,num+d[p][i].v,p);
}
int main()
{
	scanf("%d %d",&n,&s);
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d %d %d",&x,&y,&z);
		d[x].push_back({z,y});
		d[y].push_back({z,x});
		sum+=z;
	}
	trv(s,0,0);
	printf("%d",sum*2-ans);
	return 0;
}

E.扫雪系列II

  • 传统题 1000ms 128MiB

说明

大雪履盖了整个城市,市政府要求冬季服务部门尽快将一些街道(列在一份清单中)的积雪清除掉以恢复交通,整个城市由许多交叉路口和街道构成,当然任意两个交叉路口都是直接或间接连通的,清单给出了最少的街道,使得这些街道的积雪清除后任意两个交叉路口之间有且仅有一条通路,冬季服务部门只有两辆铲雪车及两名司机,他们的出发点位于某个交叉路口。 
无论街道上有没有积雪,铲雪车每前进一米都要消耗一升燃料,冬季服务部门要求司机在铲除清单上的所有街道的积雪的前提下,要求消耗燃料最少,积雪铲完后车可以停在任意的交叉路口。

输入格式

输入文件的第一行包含两个整数N和S,1≤N≤100000,1≤S≤N。N为交叉路口的总数;S为铲雪车出发的路口序号。路口的标号为1••N。 
接下来的N-1行为清单上的街道,每一行包含三个用空格隔开的整数A、B、C,表示一条从交叉路口A到交叉路口B的街道,C为该街道的长度,单位为米,1≤C≤1000。

输出格式

输出文件仅一行包含一个整数表示清除所有积雪所需的最少的燃料数量。

样例

输入数据 1

4 1
1 2 3
1 3 7
2 4 4

输出数据 1

14
#include<bits/stdc++.h>
using namespace std;
int n,s,x,y,z,sum,ans[2],st[2];
bool vis[100005];
struct node
{
	int len,nod;
};
vector<node>d[100005];
void trv(int p,int num,int t)
{
	vis[p]=true;
	if(ans[t]<num)
	{
		ans[t]=num;
		st[t]=p;
	}
	for(int i=0;i<=d[p].size()-1;i++)
		if(vis[d[p][i].len]==false)
			trv(d[p][i].len,num+d[p][i].nod,t);
}
int main()
{
	scanf("%d %d",&n,&s);
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d %d %d",&x,&y,&z);
		d[x].push_back({y,z});
		d[y].push_back({x,z});
		sum+=z;
	}
	ans[0]=ans[1]=INT_MIN;
	trv(s,0,0);
	memset(vis,false,sizeof(vis));
	trv(st[0],0,1);
	printf("%d",2*sum-ans[1]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值