bzoj1086 王室联邦 dfs

      看到题目完全不会做的样子。为什么是<=3b??这个3有什么用?n才1000是不是可以动态规划比如f[i][x]表示以i为根i在大小为x的块中?然而转移方程似乎比较复杂,应该是一个分组背包一样的东西。关键是输出分类方法,这怎么输出啊。。于是果断翻题解。
       意料之外情理之中。
一遍dfs即可。注意到以x为根节点时,其儿子s,则子树s中与s相连的节点的连通块,如果要构成一个省,既可以s作为省会还可以x作为省会。如果用s作为省会,那s的子树<b怎么办?所以以x为省会。这样将x的子树中没有标号的每超过b个就连成一个省份。当然如果以x为节点的树小于b,那就在x的父节点中操作。由于是从下往上操作,所以那些没有标号的一定与x的其中一个儿子s构成连通块。那为什么是3b呢?这样不是2b就够了吗?考虑到对于根节点r,最后还剩下小于b个的节点没有省份,这样将剩下来的点并入最后一个省份,以x为省会即可。
       考虑操作。显然这需要一个栈来维护,每次回去之前将x加入栈里面。然后栈中在当前树中的节点超过b个时就将这b个放到一个省里。

代码还是很简单的,如下(注意到代码里没有无解的情况,因为b<=n所以显然有解啊):

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2005
using namespace std;

int n,m,tot,tp,cnt,fst[N],pnt[N],nxt[N],stk[N],a[N],c[N];
void add(int aa,int bb){
	pnt[++tot]=bb; nxt[tot]=fst[aa]; fst[aa]=tot;
}
void dfs(int x,int fa){
	int p,last=tp;
	for (p=fst[x]; p; p=nxt[p]){
		int y=pnt[p]; if (y==fa) continue;
		dfs(y,x);
		if (tp-last>=m){
			c[++cnt]=x;
			while (tp>last) a[stk[tp--]]=cnt;
		}
	}
	stk[++tp]=x;
}
int main(){
	scanf("%d%d",&n,&m); int i;
	for (i=1; i<n; i++){
		int x,y; scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	dfs(1,0); while (tp) a[stk[tp--]]=cnt; 
	printf("%d\n",cnt);
	for (i=1; i<n; i++) printf("%d ",a[i]); printf("%d\n",a[n]);
	for (i=1; i<cnt; i++) printf("%d ",c[i]); printf("%d\n",c[cnt]);
}

by lych
2015.12.1

参与评论 您还未登录,请先 登录 后发表或查看评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

lych_cys

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值