感谢这个题让我进了前1000
思路(特殊条件切入):
一开始想跑网络流,但边数、点数太多,所以就需要找此题和常规网络流的区别
看到 M/2 ——>尽可能使用M/2这个条件构造解——>少于M/2的全选——>剩下的全是大于M/2的
——>如果每天全是两个以上的,必然可以(极限情况两个全取M/2次)——>一天只有一个的必选,判断合法
——>剩下的往M/2取,取满了换数
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m,a,ansl,T;
int i,j,k,l,x,y,cha[300005],gs[100005];
vector<int>o[100005];
vector<int>tu[100005];
int ans[100005];
int main()
{
scanf("%d",&T);
while(T--)
{bool keyi=true;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){ans[i]=0;tu[i].clear();
}
for(i=1;i<=n;i++){
gs[i]=0;
o[i].clear();
}
for(i=1;i<=m;i++)
{
scanf("%d",&l);
for(j=1;j<=l;j++)
{
int now;
scanf("%d",&now);
o[now].push_back(i);
tu[i].push_back(now);
}
}
for(i=1;i<=n;i++)
{
if(o[i].size()<=(m+1)/2)
{
for(j=0;j<o[i].size();j++)
{
ans[o[i][j]]=i;
}
}
}
for(i=1;i<=m;i++)
{
if(tu[i].size()==1)
{int now=tu[i][0];
gs[now]++;
ans[i]=now;
if(gs[now]>(m+1)/2)keyi=false;
}
}
for(i=1;i<=m;i++)
{
if(ans[i]==0)
{
for(j=0;j<tu[i].size();j++)
{
int now=tu[i][j];
if(gs[now]==(m+1)/2)continue;
gs[now]++;
ans[i]=now;
break;
}
}
}
if(keyi)
{
printf("YES\n");
for(i=1;i<=m;i++)
printf("%d ",ans[i]);
printf("\n");
}
else{
printf("NO\n");
}
}
}