Poj1463 及 Poj3659 树形贪心建立解

Poj1463

题目链接:http://poj.org/problem?id=1463

 

题意:给出一个树形图,在某个节点上放置一个卫兵可以管辖周围所有与该节点相连的边,问最少需要放置多少个卫兵,能管辖所有的边。

 

贪心思路是,叶节点不放置卫兵,则其父亲节点必放置卫兵以覆盖该边,自叶节点向上的过程中,如果某节点含有未被覆盖的通向子节点的边,则此节点放置卫兵。

 

 

 

Poj3659

题目链接:http://poj.org/problem?id=3659

 

题意:同样是一个树形图,在某个节点上放置一个信号塔,可以覆盖所有与其相邻的其它节点,问最少需要放置多少个信号塔,用以覆盖所有的节点。

 

乍一看与上一题一样,可是仔细分析不难发现,这一题中要求的是覆盖所有节点,即与上一题不同之处在于,如果一个节点被其子节点覆盖的话,其父节点就不需要放置信号塔

来覆盖它,这样就有边未被覆盖,但达到了此题的要求,具体做法是,对每一个节点的覆盖分三种情况考虑:

1、被子节点放置的信号塔覆盖;

2、本身放置了信号塔;

3、本身既未放置信号塔,也未被子节点覆盖。

同1463一样,实现过程中从叶节点到根进行贪心决策,叶节点置情况为3,则,如果某一节点其子节点有3 这种情况,该节点必定置2状态,否则视其是否被子节点放置情况覆

盖取1、2两种状态,   要另外说明的一点是,如果执行至根节点时,其状态为3,则是需要另外放置一个信号塔,因为没有父节点能覆盖它。

 

Poj1463 Code

 

#include<stdio.h>
#include<string.h>
int l[1508];
int s[1508];
int vis[1508];
int map[1508][16];
int n;

int Dfs(int u)
{
	int place=0,i,r=0;
	vis[u]=1;
	for(i=0;i<l[u];i++){
		if(vis[map[u][i]]) continue;
		r+=Dfs(map[u][i]);
		if(!s[map[u][i]])
			place=1;
	}
	return r+(s[u]=place);
}
int main()
{
	int i,j,u,v,e;

	while(~scanf("%d",&n)){

		memset(l,0,sizeof(l));
		memset(s,0,sizeof(s));
		memset(vis,0,sizeof(vis));

		for(i=0;i<n;i++){
			scanf("%d",&u);
			scanf(":(%d)",&e);

			for(j=0;j<e;j++){
				scanf("%d",&v);
				map[u][l[u]++]=v;
				map[v][l[v]++]=u;
			}

		}
		printf("%d\n",Dfs(0));
	}
	return 0;
}


 

Poj 3659 Code

#include<stdio.h>
#include<string.h>
struct{
	int v,next;
}edg[20016];
int s[10008];
int vis[10008];
int head[10008];
int n,e;
int Dfs(int u)
{

	int place=0,tmp,r=0;
	vis[u]=1;
	for(tmp=head[u];tmp!=-1;tmp=edg[tmp].next){
		if(vis[edg[tmp].v]) continue;
		r+=Dfs(edg[tmp].v);
		if(place==2) continue;
		if(s[edg[tmp].v]==0)place=2;
		if(s[edg[tmp].v]==2)place=1;

	}s[u]=place;//0表示当前节点未被子节点覆盖,1表被子节点覆盖,2表示
				//需要覆盖子节点。
	return r+(place>>1);//由增加的一个节点0来简化根节点的判断,即根节
						//点如果不需要覆盖子节点,又没有父节点将其覆盖
						//此种待殊情况。
}
int main()
{
	int i,u,v;

	while(~scanf("%d",&n)){

		memset(s,0,sizeof(s));
		memset(vis,0,sizeof(vis));
		memset(head,-1,sizeof(head));
		e=0;

		for(i=1;i<n;i++){

			scanf("%d%d",&u,&v);

			edg[e].v=v;edg[e].next=head[u];head[u]=e++;
			edg[e].v=u;edg[e].next=head[v];head[v]=e++;
		}edg[e].v=1;edg[e].next=head[0];head[0]=e++;

		printf("%d\n",Dfs(0));
		scanf("%d",&u);
		if(u==-1) break;
	}
	return 0;
}
/*
9
1 2
2 3
3 4
4 5
5 6
5 7
4 8
8 9

8
1 2
2 3
3 4
3 5
2 6
6 7
6 8

*/


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值