1. 程式人生 > >BZOJ1086:[SCOI2005]王室聯邦——題解

BZOJ1086:[SCOI2005]王室聯邦——題解

輸入輸出格式 lan char urn 觀察 hellip 成員 problem size

http://www.lydsy.com/JudgeOnline/problem.php?id=1086

題面源於洛谷。

題目描述

“余”人國的國王想重新編制他的國家。他想把他的國家劃分成若幹個省,每個省都由他們王室聯邦的一個成員來管理。

他的國家有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 

——————————————————————————————————————————-

歡迎訪問小兔大佬的博客:http://www.cnblogs.com/RabbitHu/p/BZOJ1086.html

由神奇的證明得知:不存在為0的情況(貌似肉眼觀察法蠻容易得出)

我們一個dfs搜下去,搜到一個子樹>=b就是一個省了,那麽省會可以設為這個子樹的根。

最後把棧中的點加入最後一個省即可,又有神奇的證明發現這樣的話大小一定<=3b。

……證明不會……

#include<cstdio>
#include<stack>
#include<cctype>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1001;
const int BIG=1000001;
const int M=200001;
const int INF=2147483647;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==-;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int to;
    int nxt;
}edge[N*2];
int n,b,cnt,head[N];
int top,idx,stk[N],blk[N],cap[N];
inline void add(int u,int v){
    cnt++;
    edge[cnt].to=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    return;
}
void dfs(int u,int f){
    int st=top;
    for(int i=head[u];i;i=edge[i].nxt){
    int v=edge[i].to;
    if(v==f)continue;
    dfs(v,u);
    if(top-st>=b){
        cap[++idx]=u;
        while(top>st)blk[stk[top--]]=idx;
    }
    }
    stk[++top]=u;
    return;
}
int main(){
    n=read();
    b=read();
    for(int i=1;i<n;i++){
    int u=read(),v=read();
    add(u,v);add(v,u);
    }
    dfs(1,0);
    while(top)blk[stk[top--]]=idx;
    printf("%d\n",idx);
    for(int i=1;i<=n;i++){
    printf("%d ",blk[i]);
    }
    putchar(\n);
    for(int i=1;i<=idx;i++){
    printf("%d ",cap[i]);
    }
    putchar(\n);
    return 0;
}

BZOJ1086:[SCOI2005]王室聯邦——題解