二分图匹配,第一次写
第一次把一个点拆成两个点+边的有向图,所以这是构图,因为原图每一个点(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了两发