District Division(ZOJ)

Ezio learned a lot from his uncle Mario in Villa Auditore. He also made some contribution to Villa Auditore. One of the contribution is dividing it into many small districts for convenience of management. If one district is too big, person in control of this district would feel tiring to keep everything in order. If one district is too small, there would be too many districts, which costs more to set manager for each district.

There are  rooms numbered from 1 to  in Villa Auditore and  corridors connecting them. Let's consider each room as a node and each corridor connecting two rooms as an edge. By coincidence, Villa Auditore forms a tree.

Ezio wanted the size of each district to be exactly , which means there should be exactly  rooms in one district. Each room in one district should have at least one corridor directly connected to another room in the same district, unless there are only one room in this district (that is to say, the rooms in the same district form a connected component). It's obvious that Villa Auditore should be divided into  districts.

Now Ezio was wondering whether division can be done successfully.

Input

There are multiple test cases. The first line of the input contains an integer  (about 10000), indicating the number of cases. For each test case:

The first line contains two integers  (), indicating the number of rooms in Vally Auditore and the number of rooms in one district.

The following  lines each contains two integers  (), indicating a corrider connecting two rooms  and .

It's guaranteed that:

  •  is a multiple of ;

  • The given graph is a tree;

  • The sum of  in all test cases will not exceed .

Output

For each test case:

  • If the division can be done successfully, output "YES" (without quotes) in the first line. Then output  lines each containing  integers seperated by one space, indicating a valid division plan. If there are multiple valid answers, print any of them.

  • If the division cannot be done successfully, output "NO" (without quotes) in the first line.

Please, DO NOT output extra spaces at the end of each line, or your answer will be considered incorrect!

Sample Input

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

Sample Output

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

题目意思为给一颗树,问能不能把这颗树拆成很多k个节点数相同的树,如果可以输出yes,且输出每颗树的节点,否则输出no,可以发现,如果以一个节点为根节点无法拆,则以其他节点为根是也一定不能拆,所以我们可以任意选一个节点为根节点,然后进行树形dp,dfs过程中,开一个dp数组,记录当前节点的子节点加上自身的节点个数,如果节点数为为k,则把当前节点的dp数组值设为0,然后继续向上dp,我们可以知道,当前节点数的子孙节点个数为所有子节点的dp值加上1(加上本身),所以状态转移方程为dp[n] += {所有子节点的dp值},这样我们在dfs的过程中,就已经把分割的方法及可行性都求出来了,最后如果根节点的dp值为0则可以,否则不行,求每个树的节点时,可以把dp值为0的节点进行dfs求一下联通块,保存节点的编号,因为题目没有要求顺序,所以保存答案可以用队列,也可以用栈,也可以用vector,只要能保存值的容器都可以,我用的是vector。

代码如下:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1e5 + 10;
vector<int>t[maxn];
int dp[maxn];
bool vis[maxn];
void dfs(int n, int k)
{
    vis[n] = 1;
    dp[n] = 1;
    for(int i = 0; i < t[n].size(); ++ i)
    {
        if(!vis[t[n][i]])
        {
            dfs(t[n][i], k);
            dp[n] += dp[t[n][i]];
        }
    }
    if(dp[n] == k)
    {
        dp[n] = 0;
    }
}
vector<int>ans;
void dfs_ans(int n)
{
    if(dp[n] == 0) return;
    vis[n] = 1;
    ans.push_back(n);
    for(int i = 0; i < t[n].size(); ++ i)
    {
        if(!vis[t[n][i]])
        {
            dfs_ans(t[n][i]);
        }
    }
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, k;
        scanf("%d%d", &n, &k);
        for(int i = 0; i <= n; ++ i)
        {
            t[i].clear();
        }
        for(int i = 1; i < n; ++ i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            t[a].push_back(b);
            t[b].push_back(a);
        }
        memset(vis, 0, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        dfs(1, k);
        if(dp[1] == 0)
        {
            printf("YES\n");
            memset(vis, 0, sizeof(vis));
            for(int i = 1; i <= n; ++ i)
            {
                if(dp[i] == 0)
                {
                    ans.clear();
                    dp[i] = 1;
                    dfs_ans(i);
                    dp[i] = 0;
                    for(int i = 0; i < ans.size()-1; ++ i)
                    {
                        printf("%d ", ans[i]);
                    }
                    printf("%d\n", ans[ans.size()-1]);
                }
            }
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}





猜你喜欢

转载自blog.csdn.net/MALONG11124/article/details/80641470
ZOJ
今日推荐