题目链接
https://codeforces.com/contest/1141/problem/G
题目大意:
n n n个城市, n − 1 n-1 n−1条路,要求用最少的公司修路,同时使得不满足条件的城市数量小于等于 k k k。当一个城市的路有两个以上相同的公司来修时,这个城市不满足题目条件。
思路:
首先统计每个节点的度,如果一个节点的度等于
m
m
m,那么这个城市一定可以由
m
m
m个不同的公司来修,这个城市一定符合条件。所以所有节点中最大的度,即使所需要最多的公司数。
由于公司越多,不满足条件的城市越少,用二分找出最少且满足条件的公司。
最后利用DFS对树进行染色,保证当前节点与父亲节点之间,以及当前节点的孩子之间所连的边不同颜色。
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
int n,k;
int dg[200010];
vector<pair<int,int>> ed[200010];
int comp=0,C[200010];
int mxd=0;
int judge(int mid){
int num=0;
for(int i=1;i<=n;i++){
if(dg[i]>mid){
num++;
if(num>k) return 0;
}
}
return 1;
}
void dfs(int u,int fa,int col){//当前节点,父亲节点,当前节点与父亲节点的边的颜色(上一条边的颜色)
int color=0;
for(auto to:ed[u]){
int nxt=to.first,ind=to.second;
if(nxt!=fa){
if(color==col){//确保与父亲节点之间的边颜色不相同
color=(color+1)%comp;
}
C[ind]=color;
dfs(nxt,u,color);
color=(color+1)%comp;//与孩子节点之间的边颜色不相同
}
}
}
int main(){
cin>>n>>k;
for(int i=1;i<=n-1;i++){
int x,y;
cin>>x>>y;
dg[x]++;
dg[y]++;
mxd=max(mxd,max(dg[x],dg[y]));//统计最大的度
ed[x].pb(mp(y,i));
ed[y].pb(mp(x,i));
}
int l=1,r=mxd;
while(l<r){//二分查找最小的公司
int mid=(l+r)>>1;
if(judge(mid)) r=mid;
else l=mid+1;
}
comp=l;
dfs(1,-1,-1);
cout<<comp<<"\n";
for(int i=1;i<=n-1;i++) cout<<C[i]+1<<" ";
cout<<"\n";
return 0;
}