题目大意:
有N个人,K个大学,每个人有Gi个心仪的学校,为集合Si,然后然后这N个人可以去任意一个且仅一个他心仪的学校,问是否可以使得K个学校每个学校都有不小于2个人去。如果没有,输出”NO”,否则输出”YES”,然后接下来K行,每行一个数,表示去第i个学校的人有几个,接下来输出那几个人去哪个学校。PS:有的人可以不去学校,只要满足每个学校有2个及以上的人去就行了,不要求N个人每个人都去上学,比如可以在家浪。。。。。。
解题思路:
首先这道题目显然可以用有上下确界的可行流做,但是太麻烦了,直接跑最大流就行了啊。
首先原点St向所有的学生连一条流量为1的边,所有的学生向他心仪的学校连一条流量为1的边,然后每个学校向汇点En连一条流量为2的边,然后跑最大流,如果最后Max?Flow=K?2说明是可行的,否则是不行的。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define Min(a,b) ((a)>(b)?(b):(a))
using namespace std;
int G[510][510]={{0}};
int f[510][510]={{0}};
int N,K;
int st=0,en;
int dist[510]={0};
int dui[510]={0};
int duip=0;
void bfs()
{
duip=0;
dui[++duip]=en;
for(int i=1;i<=duip;i++)
{
int u=dui[i];
for(int v=0;v<=en;v++)
{
if(G[v][u]-f[v][u]>0 && dist[v]>dist[u]+1)
{
dist[v]=dist[u]+1;
dui[++duip]=v;
}
}
}
return;
}
int Max_Flow(int now,int Max)
{
if(now==en) return Max;
int sum=0;
for(int i=0;i<=en;i++)
{
if(G[now][i]-f[now][i]>0 && dist[now]==dist[i]+1)
{
int tmp=Min(G[now][i]-f[now][i],Max);
tmp=Max_Flow(i,tmp);
sum+=tmp;
Max-=tmp;
f[now][i]+=tmp;
f[i][now]-=tmp;
if(Max==0) return sum;
}
}
return sum;
}
void prt()
{
for(int i=N+1;i<=en-1;i++)
{
printf("2 ");
for(int j=1;j<=N;j++)
if(f[j][i]==1)
printf("%d ",j);
puts("");
}
return;
}
int main()
{
scanf("%d%d",&N,&K);
en=N+K+1;
for(int i=1;i<=N;i++)
{
int num=0;
scanf("%d",&num);
for(int j=1;j<=num;j++)
{
int sb;
scanf("%d",&sb);
G[i][sb+N]=1;
}
G[st][i]=1;
}
for(int i=1;i<=K;i++)
G[i+N][en]=2;
int ans=0;
for(;;)
{
memset(dist,0x3f3f3f3f,sizeof(dist));
dist[en]=0;
bfs();
if(dist[st]==0x3f3f3f3f)
break;
ans+=Max_Flow(st,2e9);
if(ans==K*2) break;
}
if(ans!=K*2)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
prt();
}
return 0;
}
sgu-242 Student's Morning
时间: 2024-10-09 21:34:11