242. Stud ent's Morning
memory limit per test: 6144 KB
output: standard
In that problem there are no preferences between students, because if they have very fun party that already means that everyone of them prefers anybody from this company.
More formally, your task is, given numbers of students, selected universities and preference list of every student, to decide whether it is possible to visit all universities by at least two of students or no, and if it is possible you must output for each university numbers of students, which have to go to it in one company. One student can't be in more than one company.
Input
Output
Sample test(s)
Input
4 2
1 1
2 1 2
1 2
2 1 2
Test #2
3 2
2 1 2
2 1 2
2 1 2
Output
YES
2 1 2
2 3 4
Test #2
NO
Author: | Alexey Preobrajensky |
Resource: | --- |
Date: | October, 2003 |
网上那些用上下界的题解根本不需要那么做
甚至不需要用网络流,23MS,很容易我就用多重匹配过了
首先题目对输出一组解没有任何要求
接着一个学校只要让他去两个人就够了
那么不就是一个很水的多重匹配么
写题要多思考,不要想复杂了,多重匹配很多情况还是很好使的
#include<cstdio>
#include<cstring>
const int INF=0x7fffffff;
int mat[500][500],link[500][500];
bool usedif[500];
int k,n,high;
bool can(int t)
{
for(int i=1; i<=k; i++)
{
if(usedif[i]==0&&mat[t][i])
{
usedif[i]=1;
if(link[i][0]<2)
{
link[i][++link[i][0]]=t;
return true;
}
else
{
for(int j=1; j<=link[i][0]; j++)
if(can(link[i][j]))
{
link[i][j]=t;
return true;
}
}
}
}
return false;
}
void MaxMatch()
{
int num=0;
for(int i=1; i<=k; i++) link[i][0]=0;
for(int i=n; i>=1; i--)
{
memset(usedif,0,sizeof(usedif));
if(!can(i)) num++;
}
return ;
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
memset(mat,false,sizeof(mat));
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
scanf("%d",&y);
mat[i][y]=1;
}
}
MaxMatch();
bool flag=false;
for(int i=1;i<=k;i++)
if(link[i][0]<2)
{
flag=true;
break;
}
if(!flag)
{
printf("YES/n");
for(int i=1;i<=k;i++)
{
printf("%d %d %d/n",link[i][0],link[i][1],link[i][2]);
}
}
else printf("NO/n");
}
return 0;
}
邻接表写的网络流,还行,效率差不多
#include<cstdio>
#include<cstring>
const int N=1510;
const int M=60001;
const int inf=0x7fffffff;
int head[N];
struct Edge
{
int v,next,w;
} edge[M];
int cnt,n,k,s,t;
void addedge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int sap()
{
int pre[N],cur[N],dis[N],gap[N];
int flow=0,aug=inf,u;
bool flag;
for(int i=0; i<n; i++)
{
cur[i]=head[i];
gap[i]=dis[i]=0;
}
gap[s]=n;
u=pre[s]=s;
while(dis[s]<n)
{
flag=0;
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dis[u]==dis[v]+1)
{
flag=1;
if(edge[j].w<aug) aug=edge[j].w;
pre[v]=u;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
edge[cur[u]].w-=aug;
edge[cur[u]^1].w+=aug;
}
aug=inf;
}
break;
}
}
if(flag) continue;
int mindis=n;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)
break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
s=0;
t=n+k+1;
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++) addedge(s,i,1);
for(int i=1;i<=k;i++) addedge(i+n,t,2);
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
scanf("%d",&y);
addedge(i,y+n,1);
}
}
int nn=n;
n=n+k+2;
if(sap()==k*2)
{
printf("YES/n");
for(int j=1+nn;j<=k+nn;j++)
{
printf("2");
for(int p=head[j];p!=-1;p=edge[p].next)
{
int v=edge[p].v;
if(v==t) continue;
int w=edge[p].w;
if(w!=0) printf(" %d",v);
}
printf("/n");
}
}
else printf("NO/n");
}
return 0;
}