https://www.luogu.org/problemnew/show/P1231
听说这题也可以用匹配来做?
网络流入门题。一份书册由一本书、一本练习册和一本答案组成,给出书与练习册以及书与答案的对应关系,求最多能组成多少份书册。
将书、题、答案的n1,n2,n3三组节点间建图,n2连源点,n3连汇点,容量设为1,跑一遍最大流。
注意如果不将书拆点,则一本书可以重复使用;将n1本书拆成两个连一条边,就能保证书中流过的流量也是1了。
#include
#include
#include
using namespace std;
const int MX = 10001;
const int MXN = 1000001;
const int INF = 0x3f3f3f3f;
struct data{
int u,v,nxt,flow;
}g[MXN];
int n1,n2,n3,m1,m2,u,v,ans;
int head[MXN],tot,s,t,level[6*MX],Q[MXN];
void addEdge(int u,int v,int val) {
g[tot]=data{u,v,head[u],val};
head[u]=tot++;
g[tot]=data{v,u,head[v],0};
head[v]=tot++;
}
bool bfs(int s,int t) {
memset(level,0,sizeof(level));
int l=-1,r=0;
Q[r]=s;
level[s]=1;
while (lint u=Q[++l];
if (u==t) return true;
for (int i=head[u];i!=-1;i=g[i].nxt) {
int v=g[i].v,flow=g[i].flow;
if (level[v]==0&&flow!=0) {
Q[++r]=v;
level[v]=level[u]+1;
}
}
}
return false;
}
int dfs(int u,int maxFlow,int t) {
if (u==t) return maxFlow;
int res=0;
for (int i=head[u];i!=-1&&resint v=g[i].v,flow=min(g[i].flow,maxFlow-res);
if (level[v]==level[u]+1&&flow!=0) {
flow=dfs(v,flow,t);
g[i].flow-=flow;
g[i^1].flow+=flow;
res+=flow;
}
}
if (res==0) level[u]=MXN;
return res;
}
int main() {
scanf("%d%d%d",&n1,&n2,&n3);
memset(head,-1,sizeof(head));
scanf("%d",&m1);
while (m1--) {
scanf("%d%d",&u,&v);
addEdge(v,u+n2,1);
}
scanf("%d",&m2);
while (m2--) {
scanf("%d%d",&u,&v);
addEdge(n2+n1+u,n2+n1+n1+v,1);
}
s=0,t=n1+n1+n2+n3+1;
for (int i=1;i<=n1;++i)
addEdge(i+n2,i+n2+n1,1);
for (int i=1;i<=n2;++i)
addEdge(s,i,1);
for (int i=1;i<=n3;++i)
addEdge(i+n2+n1+n1,t,1);
while (bfs(s,t)) ans+=dfs(s,INF,t);
printf("%d\n",ans);
return 0;
}
//Version2
#include
#include
#include
using namespace std;
const int MX = 10001;
const int MXN = 1000001;
const int INF = 0x3f3f3f3f;
struct data{
int u,v,nxt,flow;
}g[MXN];
int n1,n2,n3,m1,m2,u,v,ans;
int head[MXN],tot,s,t,level[6*MX],Q[MXN];
void addEdge(int u,int v,int val) {
g[tot]=data{u,v,head[u],val};
head[u]=tot++;
g[tot]=data{v,u,head[v],0};
head[v]=tot++;
}
bool bfs(int s,int t) {
memset(level,0,sizeof(level));
int l=-1,r=0;
Q[r]=s;
level[s]=1;
while (lint u=Q[++l];
if (u==t) return true;
for (int i=head[u];i!=-1;i=g[i].nxt) {
int v=g[i].v,flow=g[i].flow;
if (level[v]==0&&flow!=0) {
Q[++r]=v;
level[v]=level[u]+1;
}
}
}
return false;
}
int dfs(int u,int maxFlow,int t) {
if (u==t) return maxFlow;
int res=0;
for (int i=head[u];i!=-1&&resint v=g[i].v,flow=min(g[i].flow,maxFlow-res);
if (level[v]==level[u]+1&&flow!=0) {
flow=dfs(v,flow,t);
g[i].flow-=flow;
g[i^1].flow+=flow;
res+=flow;
}
}
if (res==0) level[u]=MXN;
return res;
}
void dinic() {
while(bfs(s,t))
ans+=dfs(s,INF,t);
printf("%d\n",ans);
}
int main() {
scanf("%d%d%d",&n1,&n2,&n3);
memset(head,-1,sizeof(head));
scanf("%d",&m1);
while (m1--) {
scanf("%d%d",&u,&v);
addEdge(v,u+n1,1);
}
scanf("%d",&m2);
while (m2--) {
scanf("%d%d",&u,&v);
addEdge(n2+n1+u,n2+n1+n1+v,1);
}
s=0,t=n1+n1+n2+n3+1;
for (int i=1;i<=n1;++i)
addEdge(i+n2,i+n2+n1,1);
for (int i=1;i<=n2;++i)
addEdge(s,i,1);
for (int i=1;i<=n3;++i)
addEdge(i+n2+n1+n1,t,1);
dinic();
return 0;
}