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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    winform+c#之窗体之间的传值 Virus
    ASP.NET 2.0 利用 checkbox获得选中行的行号, 在footer中显示 Virus
    .NET中的winform的listview控件 Virus
    我的书橱
    Expert .NET 2.0 IL Assembler·译者序一 写在一稿完成之即
    Verbal Description of Custom Attribute Value
    AddressOfCallBacks in TLS
    下一阶段Schedule
    2008 Oct MVP OpenDay 第二天 博客园聚会
    2008 Oct MVP OpenDay 第二天 颁奖·讲座·晚会
  • 原文地址:https://www.cnblogs.com/lightac/p/12438821.html
Copyright © 2011-2022 走看看