UVA 3902 A - Network 【dfs+建树+贪心】

题意:给定n,s,k,分别表示树有n个结点,服务器位于s结点,只要客服端(叶节点为客户端)不超过服务器k距离,则都可以覆盖,问最少需要布置多少个服务器能够覆盖全部客户端

思路:1:将无根树转为有根树,并将每层的叶节点关系保存

          2:从第n-1个叶结点开始查找它的k级祖先,放置服务器在k级祖先处,并将距离k级祖先小于k距离的所有叶节点覆盖(方便下一次查找跳过)

结:第一次用c++的vector写题,不知道为啥用结构体进行模拟就是错的。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
const int maxn = 1010;
int fa[maxn],cover[maxn];
vector<int>node[maxn];
vector<int>gr[maxn];
int n,s,k;
void dfs(int u,int f,int d)//将无根树转为以s为根的有根树 
{
	int i,v,l;
	fa[u] = f;
	l = gr[u].size();
	if(l == 1&&d > k)
		node[d].push_back(u);//叶节点即客户端存入node 
	for(i = 0; i < l; i ++)
	{
		v = gr[u][i];
		if(v!=f)
			dfs(v,u,d+1);
	}
	return;
}
void dfs2(int u,int f,int d)
{
	int i,v;
	cover[u] = 1;//已被服务器覆盖则标记为1 
	for(i = 0; i < gr[u].size(); i ++)
	{
		v = gr[u][i];
		if(v!=f&&d < k)//覆盖在k范围内的叶节点 
			dfs2(v,u,d+1);
	}
	return;
}
int find()
{
	int i,j,v,ans = 0,l,u,m;
	for(i = n-1; i > k; i--)
	{
		l = node[i].size();
		for(j = 0; j < l; j ++)
		{
			v = node[i][j];
			if(cover[v])//如果叶节点即客户端已经被覆盖过,则跳过 
				continue;
			u = v;
			for(m = 0; m < k; m ++)//找到u的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));
		for(i = 0; i <= n; i ++)
		{
			node[i].clear();
			gr[i].clear();
		}
		for(i = 0; i < n-1; i ++)
		{
			scanf("%d%d",&a,&b);
			gr[a].push_back(b);
			gr[b].push_back(a);
		}
		dfs(s,-1,0);
		printf("%d\n",find());
	}
	return 0;
}
结构体实现,错了。。。
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 2010;
int n,s,k,ans;
int df[maxn],cover[maxn];
struct  node{
	int num[maxn];
	int l;
}grd[maxn],node[maxn];

void dfs(int u,int f,int d)
{
	df[u] = f;
	int L = grd[u].l ;
	if(L == 1&&d > k)
	{
		int l2 = node[u].l ;
		node[d].num[l2] = u;
		node[u].l ++;
	}
	for(int i = 0; i < L; i ++)
	{
		int v = grd[u].num[i];
		if(v != f)
			dfs(v,u,d+1);
	}
	return;
}

void dfs2(int u,int f,int d)
{
	cover[u] = 1;
	for(int i = 0; i < grd[u].l ; i ++)
	{
		int v = grd[u].num[i];
		if(v !=f &&d < k)
			dfs2(v,u,d+1);
	}
	return;
}

void find()
{
	ans = 0;
	for(int i = n-1; i > k; i--)
	{
		int L = node[i].l ;
		for(int j = 0; j < L; j ++)
		{
			int u = node[i].num[j];
			if(cover[u])
				continue;
			int v = u;
			for(int x = 0; x < k; x ++)
				v = df[v];
			dfs2(v,-1,0);
			ans ++;
		}
	}
	return;
}

int main()
{
	int t,a,b;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		scanf("%d%d",&s,&k);
		memset(grd,0,sizeof(grd));
		memset(node,0,sizeof(node));
		for(int i = 0; i < n-1; i ++)
		{
			scanf("%d%d",&a,&b);
			int L = grd[a].l ;
			int L2 = grd[b].l ;
			grd[a].num[L] = b;
			grd[a].l ++;
			grd[b].num[L2] = a;
			grd[b].l ++;
		}
		memset(df,0,sizeof(df));
		memset(cover,0,sizeof(cover));
		dfs(s,-1,0);
		find();
		printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值