POJ 1947 Rebuilding Roads 贪心

这道题第一眼看上去是树形DP,实际上网上很多标程就是用的树形DP。

不过我在想,这道题能用贪心做么?事实证明是可以的。

一开始我把题面看错了,以为根节点必须保留。

于是我每条边(或者对应的点)建立一个权值,表示砍掉这条边删掉的节点数。

设置一个变量re,表示还需要删除多少节点。

然后多次dfs,每次找到小于re的权值最大的边,把它删掉。

后来发现题看错了,题面并没有说根节点必须保留。也就是删除k条边后剩下的任意子树有p个节点就行。

那么上面那种做法貌似就失效了,因为那样做边的权值是由根节点定的。

其实说到这里也就清楚了,只需稍微改一下就过了:枚举根节点。

非常暴力的贪心,不过n最大才100,妥妥地过了。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 160
#define M 310
#define INF 99999999
using namespace std;

int n,p;
int u[M],v[M],fst[N],nxt[M],tot;
bool book[N]; int root;
int size[N]; bool del[N];
int maxa,pos,ans,mina=INF;

void add_edge(int a,int b)
{
	tot++;
	u[tot]=a; v[tot]=b;
	nxt[tot]=fst[a]; fst[a]=tot;
	tot++;
	u[tot]=b; v[tot]=a;
	nxt[tot]=fst[b]; fst[b]=tot;
}

void dfs(int p,int fa)
{
	for (int i=fst[p];i!=0;i=nxt[i])
	{
		if (v[i]!=fa)
		{
			dfs(v[i],p);
			size[p]+=size[v[i]];
		}
	}
	size[p]++;
}

void find(int p,int fa,int lim)
{
	for (int i=fst[p];i!=0;i=nxt[i])
	{
		if (v[i]!=fa && !del[v[i]])
		{
			if (size[v[i]]<=lim && size[v[i]]>maxa)
			{
				maxa=size[v[i]]; pos=v[i];
			}
			find(v[i],p,lim);
		}
	}
}

int main()
{
	scanf("%d%d",&n,&p);
	int x,y;
	for (int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add_edge(x,y);
		book[y]=true;
	}
	for (root=1;root<=n;root++)
	{
		memset(size,0,sizeof(size));
		memset(del,0,sizeof(del));
		ans=0;
		dfs(root,-1);
		int re=n-p;
		while (re>0)
		{
			maxa=0; pos=-1;
			find(root,-1,re);
			re-=maxa; del[pos]=true; ans++;
		}
		//printf("%d %d\n",root,ans);
		mina=min(mina,ans);
	}
	printf("%d",mina);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cjj490168650

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值