zoukankan      html  css  js  c++  java
  • 算法学习_匈牙利算法

    匈牙利算法

    匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法

    该算法是求解二分图的完全匹配问题

    建图:把行号放左边点集,列号放在右边点集。

    关键是求该二分图的最小边覆盖点集使得每条边都被至少一个点覆盖。

    算法模板:

    //使用bfs实现
    int dfs(int e) {
    	for(int i = 1; i <= v; ++i) {
    		if(a[e][i] && !vis[i]) {
    			vis[i] = 1;
    			if(match[i] == -1 || dfs(match[i])) {//十分重要
    				match[i] = e;//在二分图中: 行e与列i 连线
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    

     例题1

    POJ3401

    input:
    3 4
    1 1
    1 3
    2 2
    3 2
    output:
    2
    

    问题描述:在N*N的矩阵里面,有k个星球。有一个神奇的武器,每次可以消灭一行或者一列的星球,问最少使用多少次武器可以消灭所有的星球。

    求解代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    using namespace std;
    int u;
    int p[1100][1100];
    int match[1100];
    int vis[1100];
    int dfs(int e) {	//匈牙利算法
    	for(int i = 1; i <= u; ++i) {
    		if(p[e][i] && !vis[i]) {
    			vis[i] = 1;
    			if(dfs(match[i]) || match[i] == -1) {
    				match[i] = e;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    int main () {
    	int n, k;
    	while(~scanf("%d%d", &n, &k)) {
    		u = n;
    		int ans = 0;
    		memset(p, 0, sizeof p);
    		memset(match, -1, sizeof match);
    		for(int i = 1; i <= k; ++i) {
    			int x, y;
    			scanf("%d%d", &x, &y);
    			p[x][y] = 1;
    		}
    		for(int i = 1; i <= n; ++i) {
    			memset(vis, 0, sizeof vis);
    			if(dfs(i))
    				ans++;
    		}
    		printf("%d
    ", ans);
    	}
    }
    

     例题2

    Hdu 2119

    input:
    3 3 
    0 0 0
    1 0 1
    0 1 0
    0
    output:
    2
    

     题意:与上题类似,不多累述

    求解代码:

    #include <bits/stdc++.h>
    using namespace std;
    int u, v;
    bool a[110][110];
    bool vis[110];
    int match[110];
    int dfs(int e) {
    	for(int i = 1; i <= v; ++i) {
    		if(a[e][i] && !vis[i]) {
    			vis[i] = 1;
    			if(match[i] == -1 || dfs(match[i])) {//十分重要
    				match[i] = e;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    
    
    int main () {
    	int n, m;
    	while(1) {
    		cin >> n;
    		if(n == 0) {
    			break;
    		}
    		cin >> m;
    		memset(a, 0, sizeof a);
    		memset(match, -1, sizeof match);
    		for(int i = 1; i <= n; ++i) {
    			for(int j = 1; j <= m; ++j) {
    				cin >> a[i][j];
    			}
    		}
    		u = n;
    		v = m;
    		int ans = 0;
    		for(int i = 1; i <= u; ++i) {
    			memset(vis, 0, sizeof vis);
    			if(dfs(i)) {
    				ans++;
    			}
    		}
    		cout << ans << endl;
    	}
    }
    
    作者:LightAc
    出处:https://www.cnblogs.com/lightac/
    联系:
    Email: dzz@stu.ouc.edu.cn
    QQ: 1171613053
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    C结构体
    读书笔记之:C语言深度剖析
    stdin、stdout、stderr
    There is an error while getting planid. No Free partitions available
    LeetCode刷题笔录Add Binary
    UVA
    谷歌google搜索打不开、谷歌gmail邮箱及相关服务无法登录的解决的方法
    C/C++中各种类型int、long、double、char表示范围(最大最小值)
    使用java进行文件编码转换
    懂,你的App生,不懂,死!
  • 原文地址:https://www.cnblogs.com/lightac/p/12438821.html
Copyright © 2011-2022 走看看