您的位置:首页 > 其它

poj3189 二分搜索 + 二分图多重匹配

2010-08-27 21:33 417 查看
学习了下二分图多重匹配,感觉挺不错的,当点数比较少的时候,就不用转化成最大流来做了,代码复杂度较最大流低。

其实学过匈牙利二分图最大匹配,学这个也很容易,所谓多重匹配,就是Y集合某点可以和X集合多点同时匹配,也就是说Y集合点度不再是一,问X集合的最大匹配是多少。

对于X集合点u要和Y集合点v匹配,如果v点度未满,则直接uv匹配,否则,对v点的每一个父节点增广。

这题比较容易想到二分,二分最小的range值,对每一个range,枚举起点,然后用匹配判断是否可行,如果有一个起点可行,则此range值可以满足要求,继续二分迭代。

代码

/*二分搜索 + 多重二分匹配*/
#include<stdio.h>
#include<string.h>
#define NN 1004
#define BB 24

int N, B, maxRange;
int rank[NN][BB]; // rank[i][j] == k,表示barn j 在cow i 心中的rank 为 k
int cap[BB];
int fat[BB][NN];
int vis[BB];
int can(int base, int t){
int i, j;
for (i = 1; i <= B; i++){
if (rank[t][i] >= base && rank[t][i] <= maxRange + base - 1){
if (!vis[i]){
vis[i] = 1;
for (j = 1; j <= cap[i]; j++){// 如果度未满,直接匹配
if (fat[i][j] == -1){
fat[i][j] = t;
return 1;
}
}
for (j = 1; j <= cap[i]; j++){// 如果已满,对i节点的第j个父节点增广
if (can(base, fat[i][j])){
fat[i][j] = t;
return 1;
}
}
}
}
}
return 0;
}
/*二分搜索*/
int Assignment(){
int i, j, ans;
for (j = 1; j <= B - maxRange + 1; j++){ // 枚举所有range为maxRange的起点
ans = 0;
memset(fat, -1, sizeof(fat));
for (i = 1; i <= N; i++){
memset(vis, 0, sizeof(vis));
if (can(j, i)) ans++;
}
if (ans == N) return 1;
}
return 0;
}
int Binary(){
int low, hig, mid, ans;
ans = -1;
low = 1;
hig = B;
do{
mid = (low + hig) >> 1;
maxRange = mid;
if (Assignment()){
ans = mid;
hig = mid - 1;
}else low = mid + 1;
}while(low <= hig);
return ans;
}
int main()
{
int i, j, d;
scanf("%d%d", &N, &B);
for (i = 1; i <= N; i++){
for (j = 1; j <= B; j++){
scanf("%d", &d);
rank[i][d] = j;
}
}
for (i = 1; i <= B; i++){
scanf("%d", &cap[i]);
}

printf("%d\n", Binary());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: