序:
既然是个图,并且求边数的最大值。那么这就可以转化为网络流的求最大流问题。
只需要将源点与其中一子集的所有节点相连,汇点与另一子集的所有节点相连,将所有弧的流量限制置为1,那么最大流 == 最大匹配。(感谢yulemao大神的指点)
只需要在初始化的时候修改一下,就可以直接用求最大流的算法模板了。
本文代码使用EK算法, 为POJ 1469的AC代码。
EK算法解析
源代码:
/*
About: 二分图最大匹配_网络流EK算法
2017/04/22
*/
#include
#include
#include
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f
#define maxm 200005
#define maxn 10005
struct Edge{
int st, en, num;
Edge(){}
Edge(int s, int e, int n):
st(s), en(e), num(n){}
}flow[maxm];
int n, m;
int st = maxn-2, en = maxn-1;
int pre[maxn], re[maxn][maxn/10], num[maxn];
int q[maxn], curr_pos, st_pos, end_pos, ne, max_flow;
bool wh[maxn];
int cur;
int input;
char *X, *Buffer, c;
void Get_All()
{
long long file_lenth;
fseek(stdin, 0, SEEK_END);
file_lenth = ftell(stdin);
rewind(stdin);
Buffer = (char*)malloc(1*file_lenth);
fread(Buffer,1, file_lenth, stdin);
X = Buffer;
return ;
}
int Get_Int()
{
c = *X;
input = 0;
while(c < '0' || c > '9') c = *++X;
while(c >= '0' && c <= '9')
{
input = input*10+c-'0';
c = *++X;
}
return input;
}
void Add_Edge(int st, int en)
{
flow[cur] = Edge(st, en, 1);
flow[cur^1] = Edge(en, st, 0);
re[flow[cur].st][++num[flow[cur].st]] = cur;
re[flow[cur].en][++num[flow[cur].en]] = cur^1;
cur += 2;
return ;
}
void Init()
{
cur = 0;
memset(num, -1, sizeof num);
max_flow = 0;
}
static void Read()
{
int a, nums;
n = Get_Int(), m = Get_Int();
for(unsigned i = 0; i != n; ++i)
{
Add_Edge(st, i);
nums = Get_Int();
for(unsigned j = 0; j != nums; ++j)
{
a = Get_Int();
Add_Edge(i, a+n);
}
}
for(unsigned j = 1; j != m+1; ++j)
{
Add_Edge(j+n, en);
}
return ;
}
static bool Bfs(int st, int en)
{
int i, j;
st_pos = -1, end_pos = 0;
memset(wh, 0, sizeof wh);
wh[st] = 1;
q[0] = st;
while(st_pos != end_pos)
{
curr_pos = q[++st_pos];
for(i = 0; i < num[curr_pos]+1; ++i)
{
j = re[curr_pos][i];
if(flow[j].st == curr_pos && flow[j].num > 0 && !wh[flow[j].en])
{
ne = flow[j].en;
wh[ne] = 1;
pre[ne] = j;
q[++end_pos] = flow[j].en;
if(ne == en) return true;
}
}
}
return false;
}
void EK(int start_pos, int end_pos)
{
int i, minn;
while(Bfs(start_pos, end_pos))
{
minn = INF;
for(i = end_pos; i != st; i = flow[pre[i]].st)
{
minn = min(minn, flow[pre[i]].num);
}
for(i = end_pos; i != st; i = flow[pre[i]].st)
{
flow[pre[i]].num -= minn;
flow[pre[i]^1].num += minn;
}
max_flow += minn;
}
return ;
}
void Print()
{
if(max_flow == n)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
return ;
}
int main()
{
freopen("test.in", "r", stdin);
Get_All();
int times = Get_Int();
while(times --> 0)
{
Init();
Read();
EK(st, en);
Print();
}
fclose(stdin);
return 0;
}
需要注意的是,在实测中,上一篇文章所使用的匈牙利算法耗时70+ms,但是本文代码耗时600+ms。
所以利用最大流算法计算二分图的最大匹配只是借鉴思路,若不是有特殊原因,建议不使用。
至此结束。
箜瑟_qi 2017.04.22 16:02