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

过去做的都是二分图匹配 即 同一个集合里的点 互相不联通

但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决

带花树模板 用来处理一个无向图上的最大匹配 
看了一会还是不懂  抄了一遍kuangbin的模板熟悉了一下   

还有一个一般图最大权匹配 保存下来了VFK菊苣的模板题代码当作板子 http://uoj.ac/submission/16359

但愿以后的比赛永远也遇不到 .. 遇到了也能抄对 .. 抄错了也能过 .. 

R ural1099

kuangbin模板 

#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 ;
bool g[255][255];
int match[255] ;
bool inque[255] , inpath[255] , inblo[255] ;
int head , tail ;
int que[255] ;
int st , fi ;
int newbase ;
int fa[255] , base[255] ;
int cnt ;
void creag(){
    int u ,v ;
    memset(g , false , sizeof(g)) ;
    scanf("%d",&n ) ;
    while(scanf("%d%d" , &u , &v) !=EOF){
        g[u][v] = g[v][u] = true ;
    }
}
void push(int u){
    que[tail] = u ;
    tail ++ ;
    inque[u] = true ;
}
int pop(){
    int res = que[head] ;
    head ++ ;
    return res ;
}
int findca(int u , int v) {
    memset(inpath , false , sizeof(inpath)) ;
    while(true){
        u = base[u];
        inpath[u] = true ;
        if(u == st)break;
        u = fa[match[u]] ;
    }
    while(true){
        v = base[v] ;
        if(inpath[v])break;
        v = fa[match[v]] ;
    }
    return v ;
}
void reset(int u ){
    int v ;
    while(base[u] != newbase ){
        v = match[u];
        inblo[base[u]] = inblo[base[v]] = true ;
        u = fa[v] ;
        if(base[u] != newbase )fa[u] = v;
    }
}
void blocon(int u , int v ){
    newbase = findca(u,v);
    memset(inblo , false , sizeof(inblo)) ;
    reset(u) ;
    reset(v) ;
    if(base[u] != newbase )fa[u] = v ;
    if(base[v] != newbase )fa[v] = u ;
    for(int tu = 1 ;tu <= n ; tu ++ ){
        if(inblo[base[tu]]){
            base[tu] = newbase ;
            if(!inque[tu] )push(tu ) ;
        }
    }
}
void findatp(){
    memset(inque , false , sizeof(inque)) ;
    memset(fa , 0 , sizeof(fa)) ;
    for(int i = 1; i <= n ; i ++ ){
        base[i] = i ;
    }
    head = tail = 1 ;
    push(st) ;
    fi = 0 ;
    while(head < tail ){
        int u = pop() ;
        for(int v = 1; v <= n ; v ++ ){
            if(g[u][v] && (base[u] != base[v] ) && (match[u ] != v)){
                if((v == st) || ((match[v] > 0) && fa[match[v]] > 0) ){
                    blocon(u,v);
                }
                else if (fa[v] == 0) {
                    fa[v] = u ;
                    if(match[v] > 0) {
                        push(match[v]) ;
                    }
                    else {
                        fi = v ;
                        break ;
                    }
                }
            }
        }
    }
}
void ap(){
    int u ,v , w ;
    u = fi ;
    while(u > 0) {
        v = fa[u] ;
        w = match[v] ;
        match[v] = u ;
        match[u] = v;
        u = w ;
    }
}
void edmonds (){
    memset(match , 0 ,sizeof(match)) ;
    for(int u = 1; u <= n; u ++ ){
        if(match[u] == 0) {
            st = u ;
            findatp() ;
            if(fi > 0){
                ap() ;
            }
        }
    }
}

void print(){
    cnt = 0;
    for(int u = 1; u <= n ; u ++ ){
        if(match[u] > 0)cnt ++ ;
    }
    printf("%d\n",cnt);
    for(int u = 1; u <= n ; u ++ ){
        if(u < match[u]) {
            printf("%d %d\n",u , match[u]) ;
        }
    }
}
int main(){
        creag();
        edmonds() ;
        print() ;
}

S hdu4687

给出一群pair 输出那些 不在任何最大匹配中的pair 的编号

不在任何最大匹配的pair 只能是 它的两个端点上 都有必选的pair 所以这个pair不能做相邻pair的替代 因为如果替代 另一个端点上的pair就不能选了

所以 枚举每条边 把这条边的两个端点上的所以边都去掉 如果损失了两个匹配 那么这条边就不在任何一个匹配中

#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 ;
bool g[255][255];
int match[255] ;
bool inque[255] , inpath[255] , inblo[255] ;
int head , tail ;
int que[255] ;
int st , fi ;
int newbase ;
int fa[255] , base[255] ;
int cnt ;

int input[255][2] ;
int output[255] ;

bool bf[255][255] ;

void creag(){
    int u ,v ;
    memset(g , false , sizeof(g)) ;
    memset(bf , false , sizeof(bf)) ;
    for(int i = 1; i <= m ; i ++ ){
        scanf("%d%d",&u,&v);
        g[u][v] = g[v][u] = true ;
        bf[u][v] = bf[v][u] = true ;
        input[i][0] = u ;
        input[i][1] = v ;
    }
}
void push(int u){
    que[tail] = u ;
    tail ++ ;
    inque[u] = true ;
}
int pop(){
    int res = que[head] ;
    head ++ ;
    return res ;
}
int findca(int u , int v) {
    memset(inpath , false , sizeof(inpath)) ;
    while(true){
        u = base[u];
        inpath[u] = true ;
        if(u == st)break;
        u = fa[match[u]] ;
    }
    while(true){
        v = base[v] ;
        if(inpath[v])break;
        v = fa[match[v]] ;
    }
    return v ;
}
void reset(int u ){
    int v ;
    while(base[u] != newbase ){
        v = match[u];
        inblo[base[u]] = inblo[base[v]] = true ;
        u = fa[v] ;
        if(base[u] != newbase )fa[u] = v;
    }
}
void blocon(int u , int v ){
    newbase = findca(u,v);
    memset(inblo , false , sizeof(inblo)) ;
    reset(u) ;
    reset(v) ;
    if(base[u] != newbase )fa[u] = v ;
    if(base[v] != newbase )fa[v] = u ;
    for(int tu = 1 ;tu <= n ; tu ++ ){
        if(inblo[base[tu]]){
            base[tu] = newbase ;
            if(!inque[tu] )push(tu ) ;
        }
    }
}
void findatp(){
    memset(inque , false , sizeof(inque)) ;
    memset(fa , 0 , sizeof(fa)) ;
    for(int i = 1; i <= n ; i ++ ){
        base[i] = i ;
    }
    head = tail = 1 ;
    push(st) ;
    fi = 0 ;
    while(head < tail ){
        int u = pop() ;
        for(int v = 1; v <= n ; v ++ ){
            if(g[u][v] && (base[u] != base[v] ) && (match[u ] != v)){
                if((v == st) || ((match[v] > 0) && fa[match[v]] > 0) ){
                    blocon(u,v);
                }
                else if (fa[v] == 0) {
                    fa[v] = u ;
                    if(match[v] > 0) {
                        push(match[v]) ;
                    }
                    else {
                        fi = v ;
                        break ;
                    }
                }
            }
        }
    }
}
void ap(){
    int u ,v , w ;
    u = fi ;
    while(u > 0) {
        v = fa[u] ;
        w = match[v] ;
        match[v] = u ;
        match[u] = v;
        u = w ;
    }
}
void edmonds (){
    memset(match , 0 ,sizeof(match)) ;
    for(int u = 1; u <= n; u ++ ){
        if(match[u] == 0) {
            st = u ;
            findatp() ;
            if(fi > 0){
                ap() ;
            }
        }
    }
}

int print(){
    int cnt = 0;
    for(int u = 1; u <= n ; u ++ ){
        if(match[u] > 0 && u < match[u]){
            cnt ++ ;
        }
    }
    return cnt ;
}
int main(){
    while(scanf("%d%d" , &n, &m )!=EOF){
        creag();
        edmonds() ;
        int res = print() ;
        int ans = 0 ;
        for(int i = 1; i <= m; i ++ ){
            int u = input[i][0] ;
            int v = input[i][1] ;
            for(int k = 1; k <= n ; k ++ ){
                for(int j = 1; j <= n; j ++ )
                    g[k][j] = bf[k][j] ;
            }
            for(int j = 1; j <= n ; j ++ ){
                g[j][v] = g[v][j] = g[u][j] = g[j][u] = false ;

            }
            edmonds() ;
            int r = print() ;
            if(r == res - 2){
                ans ++ ;
                output[ans] = i ;
            }
        }
        printf("%d\n",ans) ;
        for(int i = 1; i <= ans ;i ++ ){
            printf("%d",output[i]) ;
            if(i != ans)printf(" ") ;
        }
        printf("\n") ; 
    }
}

二分图专题总算告一段落了 

感觉 现在只会抄模板了 .. 

明天...哈理工的最菜的三个选手 我和带我飞我的两个队友要去勇闯ecfinal题了 祝自己好运 ... 

 

posted @ 2017-01-10 18:14  天翎月  阅读(181)  评论(0编辑  收藏  举报