poj 2159 带权二分图匹配

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cassert>
using namespace std ;

const int N = 100 + 11 ;

struct Graph {
	int w[N][N] ;
	int lx[N] , ly[N] ;
	int my[N]  , slack[N] ;
	bool vx[N] , vy[N] ;
	int n , m ;
	int cntx , cnty ;

	void addinfo() {//构建二分图
		char err[N][N] ;
		int num[N][2] ;
		memset(lx , 1<<7 , sizeof(lx)) ;//设为一个极小值
		cntx = 0 , cnty = 0 ;
		for(int i = 1 ; i <= n ;  ++i) {
			for(int j = 1; j <= m ; ++j) {
				scanf(" %c" ,&err[i][j]) ;
				if(err[i][j] == 'H') {
					++cnty ;
					num[cnty][0] = i ;
					num[cnty][1] = j ;
				}
			}
		}
		int t1 , t2 ;
		for(int i = 1 ; i <= n ;++i) {
			for(int j = 1 ; j <= m ; ++j) {
				if(err[i][j] == 'm') {
					++cntx ;
					for(int k = 1 ; k <= cnty ; ++k) {
						if(num[k][0] < i) t1 = num[k][0] - i ;
						else t1 = i - num[k][0] ;
						if(num[k][1] < j) t2 = num[k][1] - j ;
						else t2 = j - num[k][1] ;
						w[cntx][k] = t1 + t2 ;
						if(w[cntx][k] > lx[cntx]) lx[cntx] = w[cntx][k] ;
					}
				}
			}
		}
	}

	bool match(int u) {
		vx[u] = true ;
		for(int i = 1; i <= cnty ; ++i) {
			if(vy[i])  continue ;
			int tmp = lx[u] + ly[i] - w[u][i] ;
			if(tmp == 0) {
				vy[i] = true ;
				if(my[i] == -1 || match(my[i])) {
					my[i] = u ;
					return true ;
				}
			}else {
				if(slack[i] > tmp) slack[i] = tmp ;
			}
		}
		return false ;
	}

	void std_fun() {
		addinfo() ;
		memset(ly , 0 ,sizeof(ly)) ;
		memset(my , -1 , sizeof(my)) ;
		for(int i = 1 ; i <= cntx ; ++i) {
			memset(slack , (1<<7)-1 , sizeof(slack)) ;
			while(true) {
				memset(vy , 0 , sizeof(vy)) ;
				memset(vx , 0 , sizeof(vx)) ;
				if(match(i)) break ;
				int d = 1<<30 ;
				for(int i = 1; i <= cnty ; ++ i) {
					if(!vy[i] && d > slack[i]) {
						d = slack[i] ;
					}
				}
				for(int i = 1; i <= cntx ;++i) {
					if(vx[i]) lx[i] -= d ;
				}
				for(int i = 1; i <= cnty ;++i) {
					if(vy[i]) ly[i] += d;
				}
			}
		}
		int sum = 0 ;
		for(int i = 1; i <= cnty ; ++i) {
			if(my[i] != -1) sum += w[my[i]][i] ;
		}
		printf("%d\n" ,-sum) ;
	}
}g ;

int main() {//freopen("/home/zqdnr/data.in" , "r" , stdin) ;
	while(scanf("%d%d" ,&g.n ,&g.m)==2 && g.n + g.m) {
		g.std_fun() ;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值