Hopcroft–Karp algorithm 总结

经过三、四天的奋斗,终于有了一点成果,看了很多书《黑书》,《图论导引》,《图论与代数结构》,《黑书指导》

及网络资料http://en.wikipedia.org/wiki/Hopcroft-Karp_algorithm

http://hi.baidu.com/czyuan_acm/blog/item/cd482e35d3947e1890ef3919.html

http://hi.baidu.com/xiaotiandm/blog/item/1fe492dbb717c96ad1164e42.html等。

也感谢这些博主,及给我启发的大牛们。

作为Hungarian算法的优化,在解决大规模的二分匹配问题时,也确实堪称一把利刃,再加上贪心初始化,就更没问题了。

实现方法确实有很多,效率也不尽相同,大牛说浙大的模板很快,但是还没看懂,最后选择了wiki上提供的方法。上面只有

伪代码,事实证明完全按照这个写行不通,参考某仁兄的代码,终于完成了,速度还行,也比较精简。

至于理论部分,由于没有完全贯通,就先不写了,附上两道题:

 

HDU 2389:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
// 625MS
// 546MS + 贪心
#include < stdio.h >
#include
< string .h >
#include
< math.h >
#define NL 3010
#define EP 1e-10

int t, m, n;
int ck[NL][ 3 ];
int arm[NL][ 2 ];
int adj[NL][NL];
int mx[NL], my[NL], dx[NL], dy[NL];
int que[NL];

inline
double dis( int x, int y)
{
return sqrt((ck[x][ 0 ] - arm[y][ 0 ]) * (ck[x][ 0 ] - arm[y][ 0 ]) + (ck[x][ 1 ] - arm[y][ 1 ]) * (ck[x][ 1 ] - arm[y][ 1 ]) + 0.0 );
}

void init()
{
int i, j;
memset(adj,
0 , sizeof (adj));
for (i = 1 ; i <= m; i ++ ) {
for (j = 1 ; j <= n; j ++ ) {
double d = dis(i, j);
if (d / ck[i][ 2 ] < t + EP) {
adj[i][
++ adj[i][ 0 ]] = j;
}
}
}
}

// 先广搜,遍历出层次标号
// 初始时将X集合中未匹配点入队,在生产匈牙利树的过程(即广搜),对于未匹配的Y集合中的点,即找到一条dis[v] = dis[u]+1;
// 对于已匹配点,dis[my[v]] = dis[v]+1,并入队,继续迭代。
bool BFS()
{
int front, rear;
int i;
front
= rear = 0 ;
for (i = 1 ; i <= m; i ++ ) {
if (mx[i] == - 1 ) {
que[rear
++ ] = i;
}
}
for (i = 0 ; i <= m; i ++ ) dx[i] = 0 ;
for (i = 0 ; i <= n; i ++ ) dy[i] = 0 ;
bool flg = false ;
while (front < rear) {
int u = que[front ++ ];
for (i = 1 ; i <= adj[u][ 0 ]; i ++ ) {
int v = adj[u][i];
if (dy[v] == 0 ) {
dy[v]
= dx[u] + 1 ;
if (my[v] == - 1 ) {
flg
= true ;
}
else {
dx[my[v]]
= dy[v] + 1 ;
que[rear
++ ] = my[v];
}
}
}
}
return flg;
}

void greed( int & ans)
{
int i, j;
for (i = 1 ; i <= m; i ++ ) {
for (j = 1 ; j <= adj[i][ 0 ]; j ++ ) {
int t = adj[i][j];
if (my[t] == - 1 ) {
mx[i]
= t;
my[t]
= i;
ans
++ ;
break ;
}
}
}
}
// DFS在层次标号的引导下遍历,类似匈牙利算法
bool DFS( int u)
{
for ( int v = 1 ; v <= adj[u][ 0 ]; v ++ ) {
int t = adj[u][v];
if (dy[t] == dx[u] + 1 ) {
dy[t]
= 0 ;
if (my[t] == - 1 || DFS(my[t])) {
my[t]
= u;
mx[u]
= t;
return true ;
}
}
}
return false ;
}

int main()
{
int T, cs = 1 ;
int i;
scanf(
" %d " , & T);
while (T -- ) {
scanf(
" %d%d " , & t, & m);
for (i = 1 ; i <= m; i ++ ) scanf( " %d%d%d " , & ck[i][ 0 ], & ck[i][ 1 ], & ck[i][ 2 ]);
scanf(
" %d " , & n);
for (i = 1 ; i <= n; i ++ ) scanf( " %d%d " , & arm[i][ 0 ], & arm[i][ 1 ]);
init();
for (i = 0 ; i <= m; i ++ ) mx[i] = - 1 ;
for (i = 0 ; i <= n; i ++ ) my[i] = - 1 ;

int ans = 0 ;
greed(ans);
while (BFS()) {
// 每次寻找极大匹配集
for (i = 1 ; i <= m; i ++ ) {
if (mx[i] == - 1 && DFS(i)) ans ++ ;
}
}
printf(
" Scenario #%d:\n " , cs ++ );
printf(
" %d\n\n " , ans);
}
return 0 ;
}

SPOJ MATCHING https://www.spoj.pl/problems/MATCHING/

数据规模比HDU 2389更大

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
// 1550ms
#include < stdio.h >
#include
< string .h >
#define CAP 50010

int n, m;
int mx[CAP], my[CAP], dis[CAP], que[CAP];
bool used[CAP];
struct Node {
int id;
struct Node * next;
}adj[CAP];

bool BFS()
{
int front, rear;
int i, j;
front
= rear = 0 ;
for (i = 1 ; i <= n; i ++ ) {
if (mx[i] < 0 ) {
dis[i]
= 0 ;
que[rear
++ ] = i;
used[i]
= true ;
}
else {
used[i]
= false ;
}
}
bool suc = false ;
while (front < rear) {
int u = que[front ++ ];
struct Node * p = & (adj[u]);
while (p -> next) {
int v = p -> next -> id;
if (my[v] < 0 ) suc = true ;
else if ( ! used[my[v]]) {
dis[my[v]]
= dis[u] + 1 ;
used[my[v]]
= true ;
que[rear
++ ] = my[v];
}
p
= p -> next;
}
}
return suc;
}

bool DFS( int u)
{
struct Node * p = & (adj[u]);
while (p -> next) {
int v = p -> next -> id;
if (my[v] < 0
|| dis[my[v]] == dis[u] + 1 && DFS(my[v])) {
my[v]
= u;
mx[u]
= v;
dis[u]
= - 1 ;
return true ;
}
p
= p -> next;
}
return false ;
}

int main()
{
int i, j, P;
int a, b;
struct Node * p;
while (scanf( " %d%d%d " , & n, & m, & P) != EOF) {
for (i = 1 ; i <= n; i ++ )
adj[i].next
= NULL;
for (i = 0 ; i < P; i ++ ) {
scanf(
" %d%d " , & a, & b);
p
= new Node;
p
-> id = b;
p
-> next = adj[a].next;
adj[a].next
= p;
}
memset(mx,
- 1 , sizeof (mx));
memset(my,
- 1 , sizeof (my));
int match = 0 ;
while (BFS()) {
for (i = 1 ; i <= n; i ++ ) {
if (mx[i] < 0 && DFS(i))
match
++ ;
}
}
printf(
" %d\n " , match);
}
return 0 ;
}

 

转载于:https://www.cnblogs.com/superbin/archive/2010/06/09/1754996.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值