Luogu P2756パイロットマッチングスキームの問題(2部グラフの最大マッチングを求める最大フロー)

リンク

トピック:二部グラフの最大一致を見つける

アイデア: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;
 } 

おすすめ

転載: blog.csdn.net/weixin_44499508/article/details/107142022