LUOGU P1402 酒店之王 (网络流)

时间:2022-06-16 06:29:45

解题思路

应该比较显然得能看出这是个网络流,将$S$与房间连边,房间与人连边,人与菜连边,菜与汇点连边,边的流量均为1。但这样是错误的,因为有可能一个人跑过去2的流量,所以要将人拆点限流。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue> using namespace std;
const int MAXN = ;
const int MAXM = ;
const int inf = 0x3f3f3f3f; inline int rd(){
int x=;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) {x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x;
} int n,p,q,head[MAXN],cnt=,to[MAXM<<],nxt[MAXM<<],val[MAXM<<];
int ans,S,T=,d[MAXN];
queue<int> Q; inline void add(int bg,int ed,int w){
to[++cnt]=ed,nxt[cnt]=head[bg],val[cnt]=w,head[bg]=cnt;
} inline bool bfs(){
while(Q.size()) Q.pop();
memset(d,,sizeof(d));d[S]=;Q.push(S);
while(Q.size()){
int x=Q.front();Q.pop();
for(register int i=head[x];i;i=nxt[i]){
int u=to[i];
if(!d[u] && val[i]){
d[u]=d[x]+;
Q.push(u);
if(u==T) return true;
}
}
}
return false;
} int dinic(int x,int flow){
if(x==T) return flow;
int res=flow,k;
for(register int i=head[x];i && res;i=nxt[i]){
int u=to[i];
if(d[u]==d[x]+ && val[i]){
k=dinic(u,min(val[i],flow));
if(!k) d[u]=;
val[i]-=k;val[i^]+=k;res-=k;
}
}
return flow-res;
} int main(){
n=rd(),p=rd(),q=rd();int x;
for(int i=;i<=p;i++) add(S,i,),add(i,S,);
for(int i=;i<=n;i++)
for(int j=;j<=p;j++){
x=rd();if(!x) continue;
add(j,i+p,),add(i+p,j,);
}
for(int i=;i<=n;i++) add(i+p,i+p+n,),add(i+p+n,i+p,);
for(int i=;i<=n;i++)
for(int j=;j<=q;j++){
x=rd();if(!x) continue;
add(i+p+n,j+n*+p,),add(j+n*+p,i+p+n,);
}
for(int i=;i<=q;i++) add(i+n*+p,T,),add(T,i+n*+p,);
while(bfs()) ans+=dinic(S,inf);
cout<<ans;
return ;
}