zoukankan      html  css  js  c++  java
  • 匈牙利算法解无边权二分图最大匹配 入门教程

    基本理论推荐阅读


    先贴个板子

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 505;
    const int maxe = 50005;
    
    int n,m,e;
    int ct,hed[maxn],ver[maxe],nt[maxe];
    void ad(int a,int b) {
    	ver[++ct]=b, nt[ct]=hed[a], hed[a]=ct;
    }
    
    int mc[maxn], vis[maxn];
    bool dfs(int x) {
    	for(int i=hed[x],y;i;i=nt[i]) if(!vis[y=ver[i]]) {
    		vis[y]=1;
    		if(!mc[y]||dfs(mc[y])) { //找到增广路
    			mc[y]=x;
    			return true;
    		}
    	}
    	return false;
    }
    
    int main()
    {
    	scanf("%d%d%d", &n,&m,&e);
    	for(int i=0,x,y;i<e;++i) {
    		scanf("%d%d", &x,&y), ad(x,y);
    	}
    	int ans = 0;
    	for(int i=1;i<=n;++i) {
    		memset(vis,0,sizeof vis);
    		if(dfs(i)) ++ans;
    		//找到一条增广路并实施增广可以使最大匹配数加一
    	}
    	cout<<ans;
    	return 0;
    }
    

    例题推荐

    [ZJOI2007]矩阵游戏
    发现无论怎么将一个有解的矩阵进行行列交换, 任意时刻其总是拥有 (n) 个黑点使得其行标号两两不同且其列标号两两不同。

    连一连画一画发现就是个无边权二分图最大匹配的问题, 一侧是行, 另一侧是列, 一条边表示一个黑点。

    贴下AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 205;
    
    int n;
    
    int ct,hed[maxn],ver[maxn*maxn],nt[maxn*maxn];
    void ad(int a,int b) {
    	ver[++ct]=b, nt[ct]=hed[a], hed[a]=ct;
    }
    int vis[maxn], mc[maxn];
    bool dfs(int x) {
    	for(int i=hed[x],y;i;i=nt[i]) if(!vis[y=ver[i]]) {
    		vis[y]=1;
    		if(!mc[y]||dfs(mc[y])) {
    			mc[y]=x;
    			return true;
    		}
    	}
    	return false;
    }
    
    int main()
    {
    	int T; cin>>T; while(T--) {
    		ct=0;
    		memset(hed,0,sizeof hed);
    		memset(mc,0,sizeof mc);
    		scanf("%d", &n);
    		for(int i=1,x;i<=n;++i) for(int j=1;j<=n;++j) {
    			scanf("%d",&x); if(x) ad(i,j);
    		}
    		int ans = 0;
    		for(int i=1;i<=n;++i) {
    			memset(vis,0,sizeof vis);
    			if(dfs(i)) ++ans;
    		}
    		if(ans==n) puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    

    棋盘覆盖
    将棋盘奇偶分类(按行标列标之和的奇偶性分类每个格子)(也叫黑白染色)。
    然后就可以二分图搞了, 注意建图的时候好好思考下细节。

    贴下AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 205;
    
    int n, t;
    bool vis[maxn][maxn];
    
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    int ct,hed[maxn*maxn],nt[maxn*maxn],ver[maxn*maxn];
    void ad(int a,int b) {
        ver[++ct]=b,nt[ct]=hed[a],hed[a]=ct;
    }
    
    int v[maxn*maxn], mc[maxn*maxn];
    bool dfs(int x) {
        for(int i=hed[x],y;i;i=nt[i]) if(!v[y=ver[i]]) {
            v[y]=1;
            if(!mc[y]||dfs(mc[y])) {
                mc[y]=x;
                return true;
            }
        }
        return false;
    }
    int main()
    {
        scanf("%d%d", &n, &t);
        for(int i=0,x,y;i<t;++i) {
            scanf("%d%d", &x,&y); vis[x][y] = true;
        }
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=n; ++j) if(!vis[i][j] && (i+j)&1) {
            for(int k=0;k<4;++k) {
                int x=i+dx[k], y=j+dy[k];
                if(x<1||x>n||y<1||y>n||vis[x][y]) continue;
                ad((i-1)*n+j, (x-1)*n+y);
            }
        }
        int ans=0;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j) if(!vis[i][j] && (i+j)&1) {
            memset(v,0,sizeof v);
            if(dfs((i-1)*n+j)) ++ans;
        }
        cout<<ans;
        return 0;
    }
    

    車的放置
    所有车的行标两两不同,列标两两不同。
    剩下的就是和 [ZJOI2007矩阵游戏] 一样, 用边表示一个格子, 然后跑无边权二分图最大匹配就行了。
    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 205;
    int n,m,t;
    bool vis[maxn][maxn];
    
    int ct,hed[maxn],ver[maxn*maxn],nt[maxn*maxn];
    void ad(int a,int b) {
        ver[++ct]=b, nt[ct]=hed[a], hed[a]=ct;
    }
    
    int mc[maxn], v[maxn];
    bool dfs(int x) {
        for(int i=hed[x],y;i;i=nt[i]) if(!v[y=ver[i]]) {
            v[y]=1;
            if(!mc[y]||dfs(mc[y])) {
                mc[y]=x;
                return true;
            }
        }
        return false;
    }
    int main()
    {
        scanf("%d%d%d", &n,&m,&t);
        for(int i=0,x,y;i<t;++i) {
            scanf("%d%d", &x,&y); vis[x][y]=1;
        }
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                if(!vis[i][j]) ad(i,j);
        int ans=0;
        for(int i=1;i<=n;++i) {
            memset(v,0,sizeof v);
            if(dfs(i)) ++ans;
        }
        cout<<ans;
        return 0;
    }
    

    导弹防御塔
    人菜,不会


    蚂蚁
    人菜,不会

  • 相关阅读:
    输入汉字转拼音
    DBGridEh(RestoreGridLayoutIni)用法
    当选中节点的同时选中父节点
    implsments
    HTML中的post和get
    SmartUpload中文乱码
    调查平台,考试系统类型的数据收集型项目
    final
    职业生涯中12个最致命的想法
    abstract
  • 原文地址:https://www.cnblogs.com/tztqwq/p/12810805.html
Copyright © 2011-2022 走看看