ZOJ - 4045District Division
题目大意:给你n个节点的树,然后让你划分这棵数使得,每一块都恰好k个节点并且两两间是连通的,也就是划分成n/k个连通集,如果可以输出YES,并输出对应的划分,否则输出NO
一开始觉得是树形dp,但不知道如何下手,看大佬的做法才恍然大悟,其实就是找子树大小刚好是k的节点,刚让它作为这一分块的根节点,它的父节点就不再记录它的子树大小,详情见代码
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 const int N=100118; 5 struct Side{ 6 int v,ne; 7 }S[2*N]; 8 vector<int> ans; 9 int n,k,is,m,sn; 10 int head[N],size[N],book[N]; 11 void add(int u,int v) 12 { 13 S[sn].v=v; 14 S[sn].ne=head[u]; 15 head[u]=sn++; 16 } 17 void fp(int u,int f) 18 { 19 for(int i=head[u];i!=-1;i=S[i].ne) 20 if(S[i].v!=f&&!book[S[i].v]) 21 { 22 book[S[i].v]=u; 23 printf(" %d",S[i].v); 24 fp(S[i].v,u); 25 } 26 } 27 int dfs(int u,int f) 28 { 29 if(!is) 30 return 0; 31 size[u]=1; 32 for(int i=head[u];i!=-1;i=S[i].ne) 33 { 34 if(S[i].v!=f&&!book[S[i].v]) 35 dfs(S[i].v,u); 36 if(S[i].v!=f&&!book[S[i].v])//如果它的这个子节点没有作为划分的子树的根节点 37 size[u]+=size[S[i].v];//那么统计上它的大小 38 } 39 if(size[u]>k)//如果它的子树大小大于k那么它分出一个大小k的子树后 40 return is=0;//剩下的会不足k个 41 if(size[u]==k) 42 { 43 ans.push_back(u);//保存作为划分的子树根节点的节点 44 book[u]=f;//并保存它的父节点,不然在输出时会PE 45 } 46 return 1; 47 } 48 int main() 49 { 50 int t,a,b; 51 scanf("%d",&t); 52 while(t--) 53 { 54 scanf("%d%d",&n,&k); 55 ans.clear(); 56 for(int i=1;i<=n;i++) 57 book[i]=0,head[i]=-1; 58 sn=0; 59 for(int i=0;i<n-1;i++) 60 { 61 scanf("%d%d",&a,&b); 62 add(a,b),add(b,a); 63 } 64 is=1; 65 if(dfs(1,-1)) 66 { 67 printf("YES "); 68 for(int i=0;i<ans.size();i++) 69 { 70 printf("%d",ans[i]); 71 fp(ans[i],book[ans[i]]); 72 printf(" "); 73 } 74 } 75 else 76 printf("NO "); 77 } 78 return 0; 79 }