题目链接
对于二分匹配,这是一道模版题(SPJ)。
二分匹配代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=105;
int N,M;
int fa[maxN];
vector<int> vt[maxN];
bool vis[maxN];
bool match(int u)
{
int len=(int)vt[u].size();
for(int i=0; i<len; i++)
{
int v=vt[u][i];
if(vis[v]) continue;
vis[v]=true;
if(fa[v]==-1 || match(fa[v]))
{
fa[v]=u;
return true;
}
}
return false;
}
int Hungery()
{
memset(fa, -1, sizeof(fa));
int ans=0;
for(int i=1; i<=M; i++)
{
memset(vis, false, sizeof(vis));
if(match(i)) ans++;
}
return ans;
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
int e1,e2;
while(scanf("%d%d",&e1,&e2)!=EOF)
{
if(e1==-1 && e2==-1) break;
vt[e2].push_back(e1);
}
int k=0;
if((k=Hungery())==0) { printf("No Solution!\n"); continue;}
else printf("%d\n",k);
for(int i=1; i<=M; i++)
{
if(fa[i]==-1) continue;
printf("%d %d\n", i, fa[i]);
}
}
return 0;
}
接下来讲一下,关于网络流Dinic的做法:
关于网络流,我用的是Dinic算法,这里用EK算法。。。也行(回头给补上去),我们通过bfs找到层,然后用邻接表的方式去记录边的关系,这里用到了个小操作,就是初始化边,我们知道一个网络流之所以能不断的更新,并且让值无限的变大就是有反向弧这么个东西,反向弧在这道问题中存在{ -1, 0, 1 },这样的取值,我这么处理,初始化所有边的值为“-1”,然后对于有关联的两个飞行员间,我们正向定义为“1”、逆向为“0”,这样,就不会遇到无限循环在{ 0,1 }之间了,并且,这么做的目的可以方便于最后的寻找,假如i->j这条边的值为0,说明被用上了,就输出这两个节点就是了。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int INF=50000;
const int maxN=205;
int N,M; //N个英飞,M个外飞
int dis[maxN], r[maxN][maxN], cot=0, tot;
bool bfs()
{
queue<int> que;
memset(dis, -1, sizeof(dis));
dis[0]=1;
que.push(0);
while(!que.empty())
{
int u=que.front();
que.pop();
for(int i=1; i<=tot; i++)
{
if(r[u][i]>0 && dis[i]==-1)
{
dis[i]=dis[u]+1;
que.push(i);
}
}
}
return dis[tot]>0?true:false;
}
int dfs(int x, int maxFlow)
{
if(x==tot) return maxFlow;
int res;
for(int i=1; i<=tot; i++)
{
if(r[x][i]>0 && dis[i]==dis[x]+1 && (res = dfs(i, min(maxFlow, r[x][i]))) )
{
r[x][i]-=res;
r[i][x]+=res;
return res;
}
}
return 0;
}
int main()
{
while(scanf("%d%d",&M,&N)!=EOF)
{
tot=N+1;
memset(r, -1, sizeof(r));
memset(dis, -1, sizeof(dis));
int e1,e2; cot=0;
while(scanf("%d%d",&e1,&e2)!=EOF)
{
if(e1==-1 && e2==-1) break;
r[e1][e2]=1;
r[e2][e1]=0;
r[0][e1]=1;
r[e2][tot]=1;
}
int res=0;
while(bfs())
{
res=dfs(0, INF);
cot+=res;
}
printf("%d\n",cot);
for(int i=1; i<=M; i++)
{
for(int j=M+1; j<=tot; j++)
{
if(r[i][j]==0) printf("%d %d\n",i,j);
}
}
}
return 0;
}
网络流EK的代码:
EK的思路与Dinic的思路相同,写EK一是为了加深自己的印象,二是看写EK的博主不多,于是就写了下,便于广大擅长EK读者阅读。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int INF=50000;
const int maxN=205;
int N,M; //N个英飞,M个外飞
int r[maxN][maxN], flow[maxN], pre[maxN], cot=0, tot;
int bfs()
{
queue<int> Q;
memset(pre, -1, sizeof(pre));
pre[0]=0;
flow[0]=INF;
Q.push(0);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
if(u==tot) break;
for(int i=1; i<=tot; i++)
{
if(r[u][i]>0 && pre[i]==-1)
{
flow[i]=min(r[u][i], flow[u]);
pre[i]=u;
Q.push(i);
}
}
}
return pre[tot]>0?flow[tot]:(-1);
}
int maxFlow()
{
int incr; //流
int sumFlow=0;
while( (incr=bfs())!=-1 )
{
int k=tot;
while(k)
{
int last=pre[k];
r[last][k]-=incr;
r[k][last]+=incr;
k=last;
}
sumFlow+=incr;
}
return sumFlow;
}
int main()
{
while(scanf("%d%d",&M,&N)!=EOF)
{
tot=N+1;
memset(r, -1, sizeof(r));
int e1,e2; cot=0;
while(scanf("%d%d",&e1,&e2)!=EOF)
{
if(e1==-1 && e2==-1) break;
r[e1][e2]=1;
r[e2][e1]=0;
r[0][e1]=1;
r[e2][tot]=1;
}
printf("%d\n",maxFlow());
for(int i=1; i<=M; i++)
{
for(int j=M+1; j<=N; j++)
{
if(r[i][j]==0) printf("%d %d\n",i, j);
}
}
}
return 0;
}