洛谷P2325 [SCOI2005]王室联邦

P2325 [SCOI2005]王室联邦

题目描述

“余”人国的国王想重新编制他的国家。他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理。

他的国家有n个城市,编号为1..n。一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路。为了防止管理太过分散,每个省至少要有B个城市,为了能有效的管理,每个省最多只有3B个城市。

每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。但是该省的任意一个城市到达省会所经过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。

一个城市可以作为多个省的省会。

聪明的你快帮帮这个国王吧!

输入输出格式

输入格式:

第一行包含两个数N,B(1<=N<=1000, 1 <= B <= N)。接下来N-1行,每行描述一条边,包含两个数,即这条边连接的两个城市的编号。

输出格式:

如果无法满足国王的要求,输出0。否则第一行输出数K,表示你给出的划分方案中省的个数,编号为1..K。第二行输出N个数,第I个数表示编号为I的城市属于的省的编号,第三行输出K个数,表示这K个省的省会的城市编号,如果有多种方案,你可以输出任意一种。

输入输出样例

输入样例#1: 复制

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

输出样例#1: 复制

3
2 1 1 3 3 3 3 2
2 1 8

说明

感谢@FlierKing提供spj

题解

dfs过程中每退出一个点,将这个点加入栈中。对于某个节点,如果他的一些子树能够构成>=B的块,则将他们作为一个快。剩余的一部分加入最后一个块中。可以证明,每次形成的块大小一定大于等于B小于2B,而剩余的一部分大小小于等于B,最后一个快不会超过3B
这种分块方法,块内不一定联通

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <bitset>
#include <cmath> 
void swap(int &a, int &b){int tmp = a;a = b, b = tmp;}
int max(int a, int b){return a > b ? a : b;}
int min(int a, int b){return a < b ? a : b;}
void read(int &x)
{
	x = 0;char ch = getchar(), c = ch;
	while(ch < '0' || ch > '9') c = ch, ch = getchar();
	while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
	if(c == '-') x = -x;
}

const int INF = 0x3f3f3f3f;
const int MAXN = 1000 + 10;

struct Edge
{
	int u, v, nxt;
	Edge(int _u, int _v, int _nxt){u = _u, v = _v, nxt = _nxt;}
	Edge(){}
}edge[MAXN << 1];
int head[MAXN], cnt, n;

void insert(int a, int b)
{
	edge[++ cnt] = Edge(a, b, head[a]), head[a] = cnt;
	edge[++ cnt] = Edge(b, a, head[b]), head[b] = cnt;
}

int belong[MAXN], stack[MAXN], top, cap[MAXN], B, num;

void dfs(int x, int pre)
{
	int now = top;
	for(int pos = head[x];pos;pos = edge[pos].nxt)
	{
		int v = edge[pos].v;
		if(pre == v) continue;
		dfs(v, x);
		if(top - now >= B)
			for(++ num, cap[num] = x;now < top;-- top)
				belong[stack[top]] = num;
	}
	stack[++ top] = x;
}

int main()
{
	read(n), read(B);
	for(int i = 1;i < n;++ i)
	{
		int tmp1, tmp2;
		read(tmp1), read(tmp2);
		insert(tmp1, tmp2);
	}
	dfs(1, 0);
	for(int i = 1;i <= n;++ i)
		if(belong[i] == 0)
			belong[i] = num;
	printf("%d\n", num);
	for(int i = 1;i <= n;++ i)
		printf("%d ", belong[i]);
	printf("\n");
	for(int i = 1;i <= num;++ i)
		printf("%d ", cap[i]);
	return 0;
} 
posted @ 2019-07-23 19:41  嘒彼小星  阅读(218)  评论(0编辑  收藏  举报