题意:给出牛,饮料还有食物的数量,每头牛给出喜欢的饮料和食物,最后求出能够满足的牛的数量
一开始觉得是二分图匹配,但是怎么配两边的呢?
遂放弃。
然后 听说网络流可以弄二分图?
很好。怎么解决 一头牛对应一种呢?把牛拆成;两个点,中间连一条边权为1的边。
搞定。那现在说一下EK算法。
戳这里就好
给个模板题 1273
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int VM=220;
const int INF=0x3f3f3f3f;
int n,m,max_flow; //max_flow是最大流
int map[VM][VM],flow[VM][VM]; // map[i][j]是每条边的容量,flow[i][j]是每条边的流量
int res[VM],pre[VM]; //res[]是每个点的剩余流量,pre[]是每个点的父亲
int EK(int src,int des){
max_flow=0;
queue<int> q;
while(!q.empty())
q.pop();
memset(flow,0,sizeof(flow)); //最开始每条边的流量都是0
while(1){
memset(res,0,sizeof(res)); //残余流量得变0,一开始所有点都没流入对吧
res[src]=INF; //源点嘛,剩余流量无限是必须的...
q.push(src); //从源点开始进行BFS找增广路
int u,v;
while(!q.empty()){
u=q.front();
q.pop();
for(v=1;v<=m;v++) //遍历所有点,找可行边
if(!res[v] && map[u][v]>flow[u][v]){ //该点剩余流量为0 且 容量大于流量,也就是找到了新的结点
pre[v]=u; //找到新结点,父节点得记录一下吧
q.push(v);
res[v]=min(res[u],map[u][v]-flow[u][v]); //如果u的剩余流量能填满uv就填满,不能的话就把u这点的流量全部流向uv
}
}
if(res[des]==0) //如果当前已经是最大流,汇点没有残余流量
return max_flow;
for(u=des;u!=src;u=pre[u]){ //如果还能增广,那么回溯,从汇点往回更新每条走过的边的流量
flow[pre[u]][u]+=res[des]; //更新正向流量 (注意这里更新的是流量,而不是容量)
flow[u][pre[u]]-=res[des]; //更新反向流量
}
max_flow+=res[des];
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(map,0,sizeof(map));
memset(pre,0,sizeof(pre));
int u,v,w;
while(n--){
scanf("%d%d%d",&u,&v,&w);
map[u][v]+=w; //有重边
}
printf("%d\n",EK(1,m));
}
return 0;
}
所以这道题为什么WA了一次
因为 我没有建后向边,也就是凡是有一条正向的这样的边都要建一条反向的边权为0的边来退流!!!!
推流!!!不然时挂的!!
1.对算法本身并没有吃透
2.建边的技巧
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3fffffff
//by mars_ch
using namespace std;
int n,f,d;
struct data
{
int f,t,nxt,c;
}e[100005];
int tot,first[605];
int flow[605][605];
int pre[605],res[605];
void add(int a,int b,int c)
{
e[tot].f=a;
e[tot].t=b;
e[tot].c=c;
e[tot].nxt=first[a];
first[a]=tot++;
}
int EK(int s,int end)
{
queue<int> q;
int max_flow=0;
while(1)
{
memset(res,0,sizeof(res));
res[s]=inf;
q.push(s);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int j=first[t];j!=-1;j=e[j].nxt)
{
int v=e[j].t;
if(!res[v] && e[j].c>flow[t][v])
{
pre[v]=t;
q.push(v);
res[v]=min(res[t],e[j].c-flow[t][v]);
}
}
}
if(res[end] == 0)
{
return max_flow;
}
for(int i=end;i!=s;i=pre[i])
{
flow[pre[i]][i]+=res[end];
flow[i][pre[i]]-=res[end];
}
max_flow+=res[end];
}
}
int main()
{
memset(first,-1,sizeof(first));
scanf("%d%d%d",&n,&f,&d);
int s=f+2*n+d+1;
for(int i=1;i<=f;i++)
{
add(0,i,1);
add(i,0,0);
}
for(int i=f+1;i<=f+n;i++)
{
add(i,i+n,1);
add(i+n,i,0);
}
for(int i=f+2*n+1;i<=f+2*n+d;i++)
{
add(i,s,1);
add(s,i,0);
}
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
for(int j=1;j<=a;j++)
{
int x;
scanf("%d",&x);
add(x,i+f,1);
add(i+f,x,0);
}
for(int j=1;j<=b;j++)
{
int x;
scanf("%d",&x);
add(i+n+f,x+f+2*n,1);
add(x+f+2*n,i+n+f,0);
}
}
int ans=EK(0,s);
printf("%d\n",ans);
return 0;
}

本文介绍如何使用网络流解决二分图匹配问题,并通过一道具体题目详细展示了Edmonds-Karp(EK)算法的实现过程及注意事项。
368

被折叠的 条评论
为什么被折叠?



