题意
某人有
n
n
n 个朋友,在
m
m
m 天中,每天会有
k
k
k 个朋友有空,问是否存在一种方案收到每个朋友出现的次数不大于
⌈
m
2
⌉
\lceil\frac{m}{2}\rceil
⌈2m⌉,存在则输出YES
和每天选择的朋友编号,否则输出 NO
。
(
1
≤
n
,
m
≤
1
0
5
)
(1≤n,m≤10^5)
(1≤n,m≤105)
分析
题目的目的是让每个人出现的天数尽可能少,那么可以先处理掉那些只有一个人的时间,然后,按照贪心,每次选择出现次数最少的人。
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+5;
int ans[N],num[N];
vector<int>day[N];
//让每个人出现的次数尽可能小,先确定能够确定的
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m,k;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
num[i]=0;
for(int i=1;i<=m;i++)
day[i].clear();
for(int i=1;i<=m;i++){
scanf("%d",&k);
int x;
for(int j=1;j<=k;j++){
scanf("%d",&x);
day[i].pb(x);
}
if(k==1){
num[x]++;
ans[i]=x;
}
}
int flag=1;
for(int i=1;i<=m;i++){
if(day[i].size()==1)
continue;
int minn=m,p=1;
for(auto x:day[i]){
if(num[x]<minn){
minn=num[x];
p=x;
}
}
num[p]++;
ans[i]=p;
}
for(int i=1;i<=n;i++){
if(num[i]>(m+1)/2){
flag=0;
break;
}
}
if(flag){
printf("YES\n");
for(int i=1;i<=m;i++)
printf("%d%c",ans[i],i==m?'\n':' ');
}
else
printf("NO\n");
}
return 0;
}