[kuangbin带你飞]专题十 匹配问题 二分图多重匹配

二分图的多重匹配问题不同于普通的最大匹配中的“每个点只能有最多一条边” 而是“每个点连接的边数不超过自己的限定数量”

最大匹配所解决的问题一般是“每个人都有一群想加入的团体 并且一个团体只能收一个人 问有多少人可以加入一个自己喜欢的团体”

而多重匹配是 “每个人都有一群想加入的团体 每个团体可以收给定的人数 问有多少人可以加入一个自己喜欢的团体”

解决这个问题 目前看貌似有三个办法

1 拆点 一个团体可以招x个人 就把它拆成x个只能招一个人的团体 进行最大匹配

2 网络流 s -> 人 cap : 1       人 -> 自己想加的团体 cap : 1     每个团体 -> t cap : 这个团体的容纳人数

3 改一改 xyl的形式 过去我们写linker[]来记录 每个团体的招人情况

现在我们创造一个数组 记录这个团体 能招多少人 现招多少人 招人的情况 这个网址讲的很简单 http://wenku.baidu.com/view/60b301c00c22590102029db2.html

专题里面的这三道题都差不多 都是用二分求一个最大最小值

M poj2289

模板题 需要做一个字符串处理

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<string>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define L long long
int n , m ;
char s[1050];
struct node{
    int many ;
    int pp[1050];
    int cnt ;
}linker[505];
bool vis[505];

vector<int >q[1050];

bool fin(int u){
    for(int i = 0 ; i< q[u].size() ; i ++ ){
        int  v = q[u][i];
        if(vis[v]){
            vis[v] = false ;
            if(linker[v].cnt < linker[v].many) {
                linker[v].pp[++linker[v].cnt] = u ;
                return true ;
            }
            else {
                for(int j = 1; j <= linker[v].many ;j ++ ){
                    if(fin(linker[v].pp[j])) {
                        linker[v].pp[j] = u ;
                        return true ;
                    }
                }
            }
        }
    }
    return false ;
}
bool xyl(int many) {
    int res = 0 ;
    for(int i = 0 ; i < m ; i ++) {
        linker[i].many = many ;
        linker[i].cnt = 0 ;
    }
    for(int i = 1 ; i <= n ; i ++ ){
        memset(vis , true , sizeof(vis )) ;
        if(fin(i)){
            res ++ ;
        }
    }
    return (res == n) ;
}
int main(){
    while(scanf("%d%d\n",&n,&m)!=EOF){
        if(n == 0 && m == 0)break;
        for(int i = 1; i<= n ; i ++)q[i].clear() ;
        for(int i = 1; i<= n ; i ++ ){
            gets(s) ;
            int len = strlen(s);
            int j ;
            for(j = 0 ; j < len ;j ++ ){
                if(s[j] == ‘ ‘){
                    j ++ ;
                    break ;
                }
            }
            int res = 0;
            for( ; j < len ; j ++ ){
                if(s[j ] == ‘ ‘){
                    q[i].push_back(res );
                    res = 0 ;
                }
                else {
                    res *= 10 ;
                    res += ( s[j] - ‘0‘ );
                }
            }
            q[i].push_back(res);
            res = 0;

        }
        int ans = -1 ;
        int l = 1 ;
        int r = 1010;
        while(l <= r){
            int mid = (l + r) / 2 ;
            if(xyl(mid)){
                ans = mid ;
                r = mid - 1 ;
            }
            else {
                l = mid + 1 ;
            }
        }
        printf("%d\n",ans);
    }
}

N poj2112

画风突然不对了 细节很多

1 给出的邻接矩阵形式 并不是最短距离 而是类似于 给出一群路来 连接每一个地点

2 给出的 0 代表这两个地点没有路

需要二分一下最大距离

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<string>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define L long long
int n , a , b , m ;
struct node{
    int many ;
    int pp[300];
    int cnt ;
}linker[300];
bool vis[300];
int c[300][300];

bool fin(int u , int jl){
    for(int v = 1; v <= a ; v ++ ){
        if(c[u][v] > jl || c[u][v] == 0){
            continue ;
        }
        if(vis[v]){
            vis[v] = false ;
            if(linker[v].cnt < linker[v].many){
                linker[v].pp[++linker[v].cnt] = u ;
                return true ;
            }
            else {
                for(int j = 1 ; j <= linker[v].many ; j ++ ){
                    if(fin(linker[v].pp[j] , jl)){
                        linker[v].pp[j] = u ;
                        return true ;
                    }
                }
            }
        }
    }
    return false ;
}
bool xyl(int jl){
    int res = 0 ;
    for(int i = 1; i <= a ;i ++){
        linker[i].cnt = 0 ;
        linker[i].many = m ;
    }
    for(int i = a + 1 ; i <= n ; i ++ ){
        memset(vis , true , sizeof(vis)) ;
        if(fin(i , jl)){
            res ++ ;
        }
    }
    return (res == b) ;
}
int main(){
    while(scanf("%d%d%d",&a , &b , & m)!= EOF){
        n = a + b;
        for(int i = 1; i <= n ; i ++ ){
            for(int j = 1 ; j <= n ; j ++ ){
                scanf("%d" , &c[i][j]) ;
            }
        }
        for(int i = 1 ; i <= n ; i ++ ){
            for(int j = 1 ; j <= n; j ++ ){
                for(int k = 1; k <= n ; k ++ ){
                    if(i == j || i == k || k == j)continue;
                    if(c[j][i] != 0 && c[i][k] != 0){
                        if(c[j][k] > 0)
                            c[j][k] = min(c[j][i] + c[i][k] , c[j][k]) ;
                        else {
                            c[j][k] = c[j][i] + c[i][k] ;
                        }
                    }
                }
            }
        }
        int l = 1 ;
        int r = 999999999 ;
        int ans = -1 ;
        while(l <= r){
            int mid = (l + r) / 2 ;
            if(xyl(mid)){
                ans = mid ;
                r = mid - 1 ;
            }
            else {
                l = mid + 1 ;
            }
        }
        printf("%d\n",ans) ;
    }
}

O poj3189

比较考验读题能力...

题意是 给出每头牛对每个谷仓的loverank

求出一个最小的范围 让每头牛最后分配的谷仓的loverank都在这个大小范围内

所以二分范围 枚举起点

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<string>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define L long long
int n , b ;
struct node{
    int many ;
    int pp[1050];
    int cnt ;
}linker[25];
bool vis[25];
int many[25];
int c[1050][25] ;

bool fin(int u , int jl , int st){
    for(int i = st; i <= st + jl - 1; i ++ ){
        int v = c[u][i] ;
        if(vis[v]) {
            vis[v] = false ;
            if(linker[v].cnt < linker[v].many) {
                linker[v].pp[++linker[v].cnt] = u ;
                return true ;
            }
            else {
                for(int j = 1 ; j <= linker[v].many ; j ++ ){
                    if(fin(linker[v].pp[j] , jl , st)){
                        linker[v].pp[j] = u ;
                        return true ;
                    }
                }
            }
        }
    }
    return false ;
}
bool xyl(int jl , int st){
    int res = 0 ;
    for(int i = 1; i <= b ;i ++ ){
        linker[i].cnt = 0;
        linker[i].many = many[i] ;
    }
    for(int i = 1 ; i <= n ; i ++ ){
        memset(vis , true , sizeof(vis)) ;
        if(fin(i , jl , st)){
            res ++ ;
        }
    }
    return (res == n) ;
}
int main(){
    while(scanf("%d%d",&n , &b)!=EOF){
        for(int i = 1; i<= n ; i ++ ){
            for(int j = 1 ; j <= b ;j ++ ){
                scanf("%d" , &c[i][j]) ;
            }
        }
        for(int i = 1; i<= b ; i ++ ){
            scanf("%d" , &many[i]) ;
        }
        int l = 1;
        int r = b ;
        int ans = -1 ;
        while(l <= r){
            int mid = (l + r) / 2 ;
            int i ;
            for(i = 1; i + mid - 1 <= b ; i ++ ){
                if(xyl(mid , i)){
                    ans = mid ;
                    r = mid - 1 ;
                    break ;
                }
            }
            if(i + mid - 1 > b){
                l = mid + 1 ;
            }
        }
        printf("%d\n",ans) ;
    }
}

可以看到Dinic跑多重匹配和跑最大匹配 都是一样的写法 只是cap不同

看起来的话 拆点法和xyl的时间复杂度都是很高的 .. Dinic不错的样子

看起来 小虎的担子 又重了一分

时间: 2024-11-16 13:07:34

[kuangbin带你飞]专题十 匹配问题 二分图多重匹配的相关文章

[kuangbin带你飞]专题十六 KMP &amp; 扩展KMP &amp; Manacher :G - Power Strings POJ - 2406(kmp简单循环节)

[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher G - Power Strings POJ - 2406 题目: Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of

[kuangbin带你飞]专题十 匹配问题 一般图匹配

过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂  抄了一遍kuangbin的模板熟悉了一下 还有一个一般图最大权匹配 保存下来了VFK菊苣的模板题代码当作板子 http://uoj.ac/submission/16359 但愿以后的比赛永远也遇不到 .. 遇到了也能抄对 .. 抄错了也能过 .. R ural1099 kuangbin模板 #include

[kuangbin带你飞]专题十 匹配问题 二分图最大权匹配

二分图最大权匹配有km算法和网络流算法 km算法模板默认解决最大权匹配的问题 而使用最小费用最大流 是解决最小权匹配问题 这两种办法都可以求最大最小权 需要两次取反 TAT 感觉讲km会很难的样子... P hdu2255 km的模板题 #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<string

【算法系列学习】DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus

A - Max Sum Plus Plus 1 https://vjudge.net/contest/68966#problem/A 2 3 http://www.cnblogs.com/kuangbin/archive/2011/08/04/2127085.html 4 5 /* 6 状态dp[i][j]有前j个数,组成i组的和的最大值.决策: 7 第j个数,是在第包含在第i组里面,还是自己独立成组. 8 方程 dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-

【算法系列学习】状压dp [kuangbin带你飞]专题十二 基础DP1 D - Doing Homework

https://vjudge.net/contest/68966#problem/D http://blog.csdn.net/u010489389/article/details/19218795 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath>

【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 G - 免费馅饼

https://vjudge.net/contest/68966#problem/G 正解一: http://www.clanfei.com/2012/04/646.html 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 #define IN

【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 E - Super Jumping! Jumping! Jumping!

https://vjudge.net/contest/68966#problem/E http://blog.csdn.net/to_be_better/article/details/50563344 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath>

【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 C - Monkey and Banana

https://vjudge.net/contest/68966#problem/C [参考]http://blog.csdn.net/qinmusiyan/article/details/7986263 [题意]:多组测试数据        每组测试数据给出n个砖块的长.宽.高,每种砖块有无穷多个,可以有三种不同的放置方法(xy;xz;yz),下面的砖要比上面的砖的长和宽都大,问最大的高度是多少. [思路]:[贪心+dp]每块砖有三种放置方法,把所有砖的所有状态都压入vector,先贪心,按面

【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 B - Ignatius and the Princess IV

http://www.cnblogs.com/joeylee97/p/6616039.html 引入一个cnt,输入元素与上一个元素相同,cnt增加,否则cnt减少,当cnt为零时记录输入元素,因为所求数字至少出现(N+1)/2次,所以最后记录元素就是所求元素 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath&g