HDU1281(二分图最大匹配)

二分图匹配,第一次写

第一次把一个点拆成两个点+边的有向图,所以这是构图,因为原图每一个点(x,y)所在方向都没有其它的二维点了,即不会有(x,..)和(..,y)的存在,所以,而且x->y有一条边,x到x不会右边,y同理,所以符合二分图原理,找出最大的x匹配元素,或者y的也行,然后遍历一下便可

/***************************************************
 author: xiecong
 FilePath : /D/acm/poj/moni.cpp/
 ***************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <map>
#include <set>
using namespace std;
typedef unsigned char uchar;

const int MAX_V=215;
int from, to, V=205;
struct macth
{

	vector<int> G[MAX_V];
	int match[MAX_V];
	bool used[MAX_V];
	void add_edge(int u, int v)
	{
		G[u].push_back(v);
	}
        bool dfs(int v)
	{
		used[v] = true;
		int Size =G[v].size();
		for (int i = 0; i < Size; i++)
		{	
			int u = G[v][i], w = match[u];
			if(v==from&&u==to) continue;
			if(w < 0 || (!used[w] && dfs(w)) )
			{
				match[v] = u;
				match[u] = v;
				return true;
			}
		}
		return false;
	}

	int bipartite_matching()
	{
		int res = 0;
		memset(match, -1, sizeof match);
		for (int v = 1; v < V; v++)
		{
			if(match[v] < 0) 
			{
				memset(used, 0, sizeof used);
				used[0] = true;
				if (dfs(v)) res++;
			}
		}
		return res;
	}
};
int main()
{
	//ios_base::sync_with_stdio(false);
	int k,ans, n, m, u[105*105], v[105*105], cnt=1;
	while(cin>>n>>m>>k)
	{
		macth erfen;
		ans= from = to = 0;
		for (int i=0;i<k;i++)
		{
			cin>>u[i]>>v[i];
			erfen.add_edge(u[i],v[i]+105);
		}
		int pre, now = erfen.bipartite_matching();
		for (int i=0;i<k;i++)
		{
			from = u[i]; to = v[i] +105;
			pre = erfen.bipartite_matching();
			//cout<<pre<<' '<<now<<endl;
			if(pre != now) ans++;
		}
		//ios_base::sync_with_stdio(true);
		printf("Board %d have %d important blanks for %d chessmen.\n",cnt++,ans,now);
		//ios_base::sync_with_stdio(false);
	}
	return 0;
}
我本来想用邻接矩阵来打标记的,但是最近学的dlx告诉我,这是个坏习惯,所以决定还是用动态数组来搞,后来有个问题比较难解决,就是删除动态数组的元素,非常不好操作,是可以做到,但是复杂度是O(n),最多有n*n个这样的操作,直接炸,所以就挂了个哨兵,from和to,再要注意下数组的界限,我不小心这样RE了两发

你可能感兴趣的:(HDU1281(二分图最大匹配))