hdu 6228

Tree

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 531 Accepted Submission(s): 338

Problem Description
Consider a un-rooted tree T which is not the biological significance of tree or plant, but a tree as an undirected graph in graph theory with n nodes, labelled from 1 to n. If you cannot understand the concept of a tree here, please omit this problem.
Now we decide to colour its nodes with k distinct colours, labelled from 1 to k. Then for each colour i = 1, 2, · · · , k, define Ei as the minimum subset of edges connecting all nodes coloured by i. If there is no node of the tree coloured by a specified colour i, Ei will be empty.
Try to decide a colour scheme to maximize the size of E1 ∩ E2 · · · ∩ Ek, and output its size.

Input
The first line of input contains an integer T (1 ≤ T ≤ 1000), indicating the total number of test cases.
For each case, the first line contains two positive integers n which is the size of the tree and k (k ≤ 500) which is the number of colours. Each of the following n - 1 lines contains two integers x and y describing an edge between them. We are sure that the given graph is a tree.
The summation of n in input is smaller than or equal to 200000.

Output
For each test case, output the maximum size of E1 ∩ E1 … ∩ Ek.

Sample Input
3
4 2
1 2
2 3
3 4
4 2
1 2
1 3
1 4
6 3
1 2
2 3
3 4
3 5
6 2

Sample Output
1
0
1

题意:给一个数,k种颜色,让你给这个树染色,如果一个边的两边的点都含有k种颜色,那么这条边是好边,求可以得到的最多的好边的数量。
做法:以任意一个点为根,拿掉任意一个边会得到两个子树,如果这两个子树的节点数都大于等于k那么这条边就是好边,然后枚举每一条边就可以得到答案了。
做法2:有点像是无向图的反拓扑序,对于每一个点保存两个值,sz[i],代表第i个点还连有多少个点,col[i],第i个点最少一边有多少个点,每次把sz[i]==1,clo[i] < k的点放进队列,进入队列的点都是坏点,然后剩余的点都是好点,好点的定义是好点跟好点的连线一定是好边,然后答案就是好点的数量-1.

#include
using namespace std;
int T,n,k;
const int N = 2e5+100;
vector<int> G[N];
int son[N],fa[N];
int ans = 0;
void dfs(int u,int f){
    fa[u] = f;
    son[u] = 1;
    for(int i = 0;i < G[u].size();i ++){
        int v = G[u][i];
        if(v == f) continue;
        dfs(v,u);
        son[u] += son[v];
    }
}

int main(){
    cin >> T;
    while(T--){
        ans = 0;
        scanf("%d %d",&n,&k);
        for(int i = 1;i <= n;i ++) G[i].clear();
        for(int i = 1;i < n;i ++){
            int u,v;
            scanf("%d %d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,-1);
        for(int i = 1;i <= n;i ++){
            for(int j = 0;j < G[i].size();j ++){
                int v = G[i][j];
                if(i == fa[v]){
                    if(son[v] >= k && n >= son[v]+k) ans ++;
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}
#include
using namespace std;
const int N = 2e5+100;
vector<int> G[N];
int sz[N];
int clo[N];
int T,n,k;
int main(){
    cin >> T;
    while(T--){
        scanf("%d %d",&n,&k);
        for(int i = 1;i <= n;i ++) G[i].clear(),sz[i] = 0,clo[i] = 1;
        for(int i = 1;i < n;i ++){
            int u,v;
            scanf("%d %d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
            sz[u]++;
            sz[v]++;
        }
        queue<int> que;
        for(int i = 1;i <= n;i ++)if(sz[i] == 1&&k!= 1)que.push(i),sz[i] = 0;
        int cnt = 0;
        while(!que.empty()){
            int now = que.front();
            cnt ++;
            que.pop();
            for(int i = 0;i < G[now].size();i ++){
                int v = G[now][i];
                if(sz[v]){
                    clo[v] += clo[now];
                    sz[v] --;
                    if(sz[v] == 1&&clo[v] < k){
                        que.push(v);
                        sz[v] = 0;
                    }
                }
            }
        }
        int ans = n-cnt;
        if(ans) ans --;
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(算法理解,hdu)