トピック:二部グラフの最大一致を見つける
アイデア:2部グラフの最大マッチングにはハンガリーのアルゴリズムがありますが、ネットワークフローによって解決することもできます。2部グラフの左側に設定されたポイントをAに設定し、2部グラフの右側に設定されたポイントをBに設定します。AからBへの有向エッジを接続し、エッジの重みは1です。スーパーソースとスーパーシンクを設定します。スーパーソースは有向エッジをAセットに接続し、Bセットは有向エッジをスーパーシンクに接続します(エッジの重みは1)。ディニックアルゴリズムを使用して、最大フローを見つけます。最大フローは最大マッチングであり、マッチングエッジは、フォワードエッジの中でフローが0でないエッジです。
コード:
#include <bits/stdc++.h>
#define ll long long
#define pi pair<int,int>
#define mk make_pair
#define pb push_back
using namespace std;
const int maxn = 105 inf = 2e9+10000;
struct Edge{
int from,to,cap,flow;
};
struct Dinic{
int n,m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n)
{
this->n=n;
for(int i=0;i<=n;i++)g[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap)
{
edges.push_back((Edge){
from,to,cap,0});
edges.push_back((Edge){
to,from,0,0});
m=edges.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<g[x].size();i++)
{
Edge& e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x,int a)
{
if(x==t||a==0)return a;
int flow=0,f;
for(int& i=cur[x];i<g[x].size();i++)
{
Edge& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int Maxflow(int s,int t,int need)
{
this->s=s;
this->t=t;
int flow=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow+=DFS(s,inf);
if(flow>=need)return flow;
}
return flow;
}
vector<int> Mincut()
{
vector<int>ans;
for(int i=0;i<edges.size();i++)
{
Edge& e=edges[i];
if(vis[e.from]&&!vis[e.to]&&e.cap>0)
ans.push_back(i);
}
return ans;
}
void Reduce()
{
for(int i=0;i<edges.size();i++)
edges[i].cap-=edges[i].flow;
}
void ClearFlow()
{
for(int i=0;i<edges.size();i++)
edges[i].flow=0;
}
}sol;
int main()
{
int m,n;
scanf("%d%d",&m,&n);
int u,v;
while(~scanf("%d%d",&u,&v))
{
if(u == -1)break;
sol.AddEdge(u,v,1);
}
int s = n+1;
int t = s+1;
for(int i=1;i<=m;i++) {
sol.AddEdge(s,i,1);
}
for(int i=m+1;i<=n;i++) {
sol.AddEdge(i,t,1);
}
int ans = sol.Maxflow(s,t,inf);
printf("%d\n",ans);
for(int i=0;i<sol.edges.size();i++)
{
if(sol.edges[i].from <= m && sol.edges[i].flow > 0)printf("%d %d\n",sol.edges[i].from,sol.edges[i].to);
}
return 0;
}