N - Network UVALive - 3902 【链式前向星应用】

11 篇文章 0 订阅
9 篇文章 0 订阅

之前写过这道题目的博客,用c++实现的前向星博客地址~~

感觉自己不是很理解vector的存储方式,所以用结构体去存图(没有学过c++,所以不敢轻易用自己不熟悉的东西),结果WA,后来在和大佬的沟通中才知道原来这是用vector去实现的前向星(以存储边的方式存储图),百度找了下链式前向星,自己理解之后,终于把这道题用自己喜欢的方式写过了~~撒花~~


#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1010;
int fa[maxn],cover[maxn],cnt,cnt2;
int head[maxn],head2[maxn];
struct node{
	int to,next;
};
struct node edge[maxn*100],Node[maxn*100];
int n,s,k;

void Add(int u,int to)//存储无根树的邻接表 
{
	edge[cnt].to = to;
	edge[cnt].next = head[u];
	head[u] = cnt ++;
	return;
}
void Add2(int u,int to)//存储叶节点的邻接表 
{
	Node[cnt2].to = to;
	Node[cnt2].next = head2[u];
	head2[u] = cnt2++;
	return;
}
void dfs(int u,int f,int d)//建以s为根的有根树 
{
	int i,v,l,sum = 0,flag=0;
	fa[u] = f;
	for(i = head[u];i != -1;i = edge[i].next)
	{
		sum ++;
		if(sum > 1)//如果u连接的结点超过1个,说明不是叶结点 
		{
			flag = 1;
		}
	}
	if(!flag&&d > k)
		Add2(d,u);//距离根s超过k的叶结点存入邻接表 
	
	for(i = head[u]; i != -1; i = edge[i].next)
	{
		v = edge[i].to;
		if(v != f)
			dfs(v,u,d+1);//继续建树 
	}
	return;
}
void dfs2(int u,int f,int d)
{
	int i,v;
	cover[u] = 1;//在k范围内的结点,全部覆盖 
	for(i = head[u]; i != -1; i = edge[i].next )
	{
		v = edge[i].to;
		if(v != f&&d < k)//如果v结点仍在k范围内,则继续覆盖 
			dfs2(v,u,d+1);
	}
	return;
}
int find()
{
	int i,j,v,ans,l,u,m;
	ans = 0;
	for(i = n-1; i > k; i--)
	{
		for(j = head2[i]; j != -1; j = Node[j].next)//遍历覆盖每个叶结点i所连接的结点 
		{
			v = Node[j].to;
			if(cover[v])//如果已经覆盖过,跳过 
				continue;
			u = v;
			for(m = 0; m < k; m ++)//找到该结点v的k级祖先 
				u = fa[u];
			dfs2(u,-1,0);
			ans ++;//记录服务器个数 
		}
	}
	return ans;
}
int main()
{
	int t,i,j,a,b;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		scanf("%d%d",&s,&k);
		memset(fa,0,sizeof(fa));//存结点间的关系 
		memset(cover,0,sizeof(cover));//记录结点是否被覆盖 
		memset(head,-1,sizeof(head));
		memset(head2,-1,sizeof(head2));
		cnt = cnt2 = 0;//边的编号 
		for(i = 0; i < n-1; i ++)
		{
			scanf("%d%d",&a,&b);
			Add(a,b);
			Add(b,a);
		}
		dfs(s,-1,0);
		printf("%d\n",find());
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值