糯米

TI DaVinci, gstreamer, ffmpeg
随笔 - 167, 文章 - 0, 评论 - 47, 引用 - 0
数据加载中……

POJ 3189 Steady Cow Assignment 二分图的多重匹配

思路:

这题完全不懂,看了这份大牛的解题报告
http://hi.baidu.com/winterlegend/blog/item/2411981e8fd0ed6bf724e45e.html
发现吗的太牛逼了!

首先二分图匹配,正常情况下,都是单个单个的点这样匹配、
但是像这道题,右边的点一个可以匹配好几个左边的点。也是用匈牙利算法,不过要做少少修改。

枚举答案的时候,有两种方法:
一个是移动区间的方法。复杂度O(B)。注意,只移动区间右边的时候不用重新匹配,只需要接着上次没匹配完的继续匹配就行了
一个是二分法。复杂度 O(B lgB)
由于数据的问题,这两种方法时间相差无几。在 16ms 和 32ms 之间。

#include <stdio.h>

struct barn {
    
int link[1024], cnt, vis, cap;
}
;
struct cow {
    
int rank[32];
}
;

struct barn barns[32];
struct cow cows[1024];
int start, end, last_pos;
int N, B, tm;

int dfs(int c)
{
    
int i, j;
    
struct barn *b;

    
for (i = start; i <= end; i++{
        b 
= &barns[cows[c].rank[i]];
        
if (b->vis == tm)
            
continue;
        b
->vis = tm;
        
if (b->cnt < b->cap) {
            b
->link[b->cnt++= c;
            
return 1;
        }

        
for (j = 0; j < b->cap; j++)
            
if (dfs(b->link[j])) {
                b
->link[j] = c;
                
return 1;
            }

    }

    
return 0;
}


inline 
void init()
{
    
int i;

    
for (i = 1; i <= B; i++)
        barns[i].cnt 
= 0;
    last_pos 
= 1;
}


inline 
int match()
{
    
int i, j;

    
for (i = last_pos; i <= N; i++{
        tm
++;
        
if (!dfs(i))
            
break;
    }

    last_pos 
= i;
    
return i > N;
}


int main()
{
    
int i, j, ans;

    freopen(
"e:\\test\\in.txt""r", stdin);

    scanf(
"%d%d"&N, &B);
    
for (i = 1; i <= N; i++)
        
for (j = 1; j <= B; j++)
            scanf(
"%d"&cows[i].rank[j]);
    
for (i = 1; i <= B; i++)
        scanf(
"%d"&barns[i].cap);
    
#if 0
    
// O(B)
    ans = B;
    start 
= end = 1;
    
while (start <= B && end <= B) {
        init();
        
while (end <= B && !match())
            end
++;
        
if (end - start + 1 < ans)
            ans 
= end - start + 1;
        start
++;
    }

#else
    
// O(B*lgB)
    int l, r, m;

    l 
= 1;
    r 
= B;
    
while (l <= r) {
        m 
= (l + r) / 2;
        
for (start = 1; start <= B - m + 1; start++{
            end 
= start + m - 1;
            init();
            
if (match())
                
break;
        }

        
if (start == B - m + 2{
            
// failed
            l = m + 1;
        }
 else 
            r 
= m - 1;
    }

    ans 
= r + 1;
#endif

    printf(
"%d\n", ans);

    
return 0;
}

posted on 2010-04-26 15:34 糯米 阅读(537) 评论(0)  编辑 收藏 引用 所属分类: POJ


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理