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<bits/stdc++.h>
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<bits/stdc++.h>
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;
}