原题链接
分析
先大致讲一下题意:
题目给定p道菜,q个房间和n个客人。
每个客人满意的条件当且仅当那个客人分配到的房间和菜都是自己喜欢的。
想都不想直接网络流,裸题。(但是因为没看清题意一开始疯狂30分)
模型:
- 把每道菜,每个客人,每个房间看成点,有喜欢关系的就连有向边,容量为1。
- 超级源向每一个菜,每个房间向超级汇连有向边,容量为1。
- 客人拆点,入点向出点连一条容量为1的边。
这样子只要跑一边网络流求出最大流就行了。。(感觉没有紫题难度)
代码
#include <bits/stdc++.h>
using namespace std;
const int inf=1<<31-1;
queue <int> q;
int n,p,w,s=0,t;
int rm[109][109],tmp[109],d[529],flow,maxflow;
int head[529],ver[300009],next[300009],edge[300009],tot=1;
void add(int x,int y){
ver[++tot]=y;edge[tot]=1;next[tot]=head[x];head[x]=tot;
ver[++tot]=x;edge[tot]=0;next[tot]=head[y];head[y]=tot;
}
bool bfs();
int dinic(int x,int flow);
int main()
{
int tt;
scanf("%d%d%d",&n,&p,&w);
t=p+2*n+w+1;
for(int i=1;i<=p;i++)add(s,i);
for(int i=1;i<=n;i++)
for(int j=1;j<=p;j++){
scanf("%d",&tt);
if(tt)add(j,i+p);
}
for(int i=1;i<=n;i++)add(i+p,i+p+n);
for(int i=1;i<=n;i++){
for(int j=1;j<=w;j++){
scanf("%d",&tt);
if(tt)add(p+n+i,p+2*n+j);
}
}
for(int i=1;i<=w;i++)add(p+2*n+i,t);
while(bfs())
while(flow=dinic(s,inf))maxflow+=flow;
cout<<maxflow<<endl;
return 0;
}
bool bfs(){
memset(d,0,sizeof(d));
while(q.size())q.pop();
q.push(s);d[s]=1;
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=next[i]){
if(!d[ver[i]] && edge[i]){
d[ver[i]]=d[x]+1;
q.push(ver[i]);
if(ver[i]==t)return true;
}
}
}
return false;
}
int dinic(int x,int flow){
if(x==t)return flow;
int res=flow,k;
for(int i=head[x];i&&res;i=next[i]){
if(edge[i] && d[ver[i]]==d[x]+1){
k=dinic(ver[i],min(flow,edge[i]));
if(!k)d[ver[i]]=0;
edge[i]-=k;
edge[i^1]+=k;
res-=k;
}
}
return flow-res;
}