二分图小结

1.hdu1045

题意:给出一张图,图中'X'表示wall,'.'表示空地,可以放置blockhouse  

同一条直线上只能有一个blockhouse,除非有wall隔开,问在给出的图中  

最多能放置多少个blockhouse  

每个边界与X都可以看成是点,.是边连的是离它最近的上面左面的两个边或者X

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
const int maxa = 40;
char mp[maxa][maxa];
int num[maxa][maxa];
int main(){
    int n;
    while(scanf("%d", &n), n){
        for(int i = 0; i <= n; i++){
            for(int k = 0; k <= n; k++){
                mp[i][k] = 'X';
            }
        }
        for(int i = 1; i <= n; i++){
            scanf("%s", mp[i]+1);
        }
        /*for(int i = 0; i <= n; i++){
            printf("%s\n", mp[i]);
        }*/
        int nn = 0;
        for(int i = 0;i <= n; i++){
            for(int k = 0; k <= n; k++){
                if(mp[i][k] == 'X')
                    num[i][k] = nn++;
            }
        }
        for(int i = 0; i < nn; i++){
            g[i].clear();
        }
        for(int i = 1 ;i <= n; i++){
            for(int k = 1; k <= n; k++){
                int x, y;
                if(mp[i][k] == '.'){
                    for(int j = k-1; j >= 0; j--){
                        if(mp[i][j] == 'X'){
                            x = num[i][j];
                            break;
                        }
                    }
                    for(int j = i-1; j >= 0; j--){
                        if(mp[j][k] == 'X'){
                            y = num[j][k];
                            break;
                        }
                    }
                    //printf("%d %d\n", x, y);
                    g[x].push_back(y);
                }
            }
        }
        Nx = nn;
        printf("%d\n", MaxMatch());
    }
}
View Code

 

2.hdu3605

题意:有 n 个人选择 m 个星球居住,选择情况和星球居住上限有限制,问是否能全部满足要求。
状态压缩+二分图

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define MAXM 555555
#define MAXN 2222
struct Edge{
    int v,cap,next;
}edge[MAXM];

int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int level[MAXN];
int gap[MAXN];
int n,m;
int NV,NE;
void init(){
    NE = 0;
    memset(head, -1, sizeof(head));
}
int SAP(int vs,int vt){
    memset(pre,-1,sizeof(pre));
    memset(level,0,sizeof(level));
    memset(gap,0,sizeof(gap));
    for(int i=0;i<=NV;i++)cur[i]=head[i];
    int u=pre[vs]=vs,maxflow=0,aug=-1;
    gap[0]=NV;
    while(level[vs]<NV){
loop:
        for(int &i=cur[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&level[u]==level[v]+1){
                aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap));
                pre[v]=u;
                u=v;
                if(v==vt){
                    maxflow+=aug;
                    for(u=pre[u];v!=vs;v=u,u=pre[u]){
                        edge[cur[u]].cap-=aug;
                        edge[cur[u]^1].cap+=aug;
                    }
                    aug=-1;
                }
                goto loop;
            }
        }
        int minlevel=NV;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap&&minlevel>level[v]){
                cur[u]=i;
                minlevel=level[v];
            }
        }
        gap[level[u]]--;
        if(gap[level[u]]==0)break;
        level[u]=minlevel+1;
        gap[level[u]]++;
        u=pre[u];
    }
    return maxflow;
}

void addedge(int u,int v,int cap,int cc=0){

    //printf("*%d %d %d\n", u, v, cap);
    edge[NE].cap=cap;edge[NE].v=v;
    edge[NE].next=head[u];head[u]=NE++;

    edge[NE].cap=cc;edge[NE].v=u;
    edge[NE].next=head[v];head[v]=NE++;
}

int num[(1<<11) + 100];
int main(){
    int n, m;
    while(scanf("%d%d", &n, &m)!=EOF){          //将所有的点压缩到1~(1<<m) - 1  num 表示这样的人有多少
        init();
        memset(num, 0, sizeof(num));
        for(int i =0;i < n; i++){
            int id = 0;
            for(int k = 0; k < m; k++){
                int x;
                scanf("%d", &x);
                if(x){
                    id += 1<<k;
                }
            }
            num[id] ++;
        }
        for(int i = 0;i < m; i++){
            int x;
            scanf("%d", &x);
            num[(1<<m) + i] = x;                //星球的点变成(1<<m) + i num表示每个星球能够承载的人数
        }
        int src = (1<<m) +m + 1;
        int sink = (1<<m) + m +2;
        NV = sink+1;
        for(int i = 0;i < (1<<m); i++){
            addedge(src, i, num[i]);                //从起点到每种人建立一条人数的边
            for(int k = 0; k < m;k ++){
                if((1<<k) & i){
                    addedge(i,(1<<m) + k, num[i]);          //每种人到对应的每个星球都建立一条人数的边
                }
            }
        }
        for(int i =0 ;i < m; i++){
            addedge(i+(1<<m), sink, num[i+(1<<m)]);     //星球到终点建立一条星球能承载最大人数的边
        }
        //printf("%d\n", SAP(src, sink));
        if(SAP(src, sink) == n) printf("YES\n");
        else printf("NO\n");
    }
}
View Code

 

3.hdu 5093

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
const int maxa = 400;
char mp[maxa][maxa];
int num[maxa][maxa];
int main(){
    int n, m;
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        for(int i = 0; i <= n; i++){
            for(int k = 0; k <= m; k++){
                mp[i][k] = '#';
            }
        }
        for(int i = 1; i <= n; i++){
            scanf("%s", mp[i]+1);
        }
        /*for(int i = 0; i <= n; i++){
            printf("%s\n", mp[i]);
        }*/
        int nn = 0;
        for(int i = 0;i <= n; i++){
            for(int k = 0; k <= m; k++){
                if(mp[i][k] == '#')
                    num[i][k] = nn++;
            }
        }
        for(int i = 0; i < nn; i++){
            g[i].clear();
        }
        for(int i = 1 ;i <= n; i++){
            for(int k = 1; k <= m; k++){
                int x, y;
                if(mp[i][k] == '*'){
                    for(int j = k-1; j >= 0; j--){
                        if(mp[i][j] == '#'){
                            x = num[i][j];
                            break;
                        }
                    }
                    for(int j = i-1; j >= 0; j--){
                        if(mp[j][k] == '#'){
                            y = num[j][k];
                            break;
                        }
                    }
                    //printf("%d %d\n", x, y);
                    g[x].push_back(y);
                }
            }
        }
        Nx = nn;
        printf("%d\n", MaxMatch());
    }
}
View Code

 

4.HDU 1281

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=111;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
int g[MAXN][MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int v =0 ; v < Ny; v++){
            if(g[u][v] && dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int v = 0; v < Ny; v++){
        if(g[u][v] && !vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
const int maxa = 105 * 111;
int x[maxa], y[maxa];
int main(){
    int n, m, q;
    int cas = 1;
    while(scanf("%d%d%d", &n, &m, &q)!=EOF){
        memset(g, 0, sizeof(g));
        for(int i =0 ;i < q; i++){
            scanf("%d%d", &x[i], &y[i]);
            g[x[i]][y[i]] = 1;
        }
        Nx = n+1;
        Ny = m+1;
        int sum = MaxMatch();
        int ans = 0;
        for(int i =0 ;i < q; i++){
            g[x[i]][y[i]] = 0;
            if(MaxMatch() < sum) ans ++;
            g[x[i]][y[i]] = 1;
        }
        printf("Board %d have %d important blanks for %d chessmen.\n", cas++, ans, sum);
    }
}
View Code

 

5.HDU 2063

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
int main(){
    int q, m, n;
    while(scanf("%d", &q)!=EOF){
        if(q == 0) return 0;
        scanf("%d%d", &m, &n);

        for(int i = 1; i <= m; i++){
            g[i].clear();
        }
        while(q--){
            int x, y;
            scanf("%d%d", &x, &y);
            g[x].push_back(y);
        }
        Nx = m+1;
        printf("%d\n", MaxMatch());
    }
}
View Code

 

6.POJ 3020

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
const int maxa =111;
char mp[maxa][maxa];
int num[maxa][maxa];
int move[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int main(){
    int t, n, m;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        for(int i = 0;i < n; i++){
            scanf("%s", mp[i]);
        }
        int sum = 0;
        for(int i = 0; i < n; i++){
            for(int k = 0;k < m; k++){
                if(mp[i][k] == '*'){
                    sum ++;
                }
            }
        }
        Nx = 0;
        for(int i =0 ;i < n; i++){
            for(int k =0 ;k < m; k++){
                num[i][k] = Nx ++;
            }
        }
        for(int i =0;i < Nx; i++){
            g[i].clear();
        }
        for(int i = 0;i < n; i++){
            for(int k = 0; k < m; k++){
                if((i+k) %2 == 1 && mp[i][k] == '*'){
                    for(int j = 0; j < 4;j++){
                        int x = i+ move[j][0], y = k + move[j][1];
                        if(0 <= x && x < n && 0 <= y && y < m && mp[x][y] == '*'){
                            g[num[i][k]].push_back(num[x][y]);
                        }
                    }
                }
            }
        }
        //printf("%d\n", sum);
        printf("%d\n", sum -MaxMatch());
    }
}
View Code

 

7.POJ 2446

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
const int maxa =111;
char mp[maxa][maxa];
int num[maxa][maxa];
int MOVE[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int main(){
    int n, m, q;
    while(scanf("%d%d%d", &n, &m , &q)!=EOF){

        int sum ;
        for(int i =0 ;i < n; i++){
            for(int k =0 ;k < m;k ++){
                mp[i][k] = '*';
            }
        }
        while(q--){
            int x, y;
            scanf("%d%d", &y, &x);
            x--, y--;
            mp[x][y] = '&';
        }
        Nx = 0;
        for(int i =0 ;i < n; i++){
            for(int k =0 ;k < m; k++){
                num[i][k] = Nx ++;
            }
        }
        for(int i =0;i < Nx; i++){
            g[i].clear();
        }
        for(int i = 0;i < n; i++){
            for(int k = 0; k < m; k++){
                if((i+k) %2 == 1 && mp[i][k] == '*'){
                    for(int j = 0; j < 4;j++){
                        int x = i+ MOVE[j][0], y = k + MOVE[j][1];
                        if(0 <= x && x < n && 0 <= y && y < m && mp[x][y] == '*'){
                            g[num[i][k]].push_back(num[x][y]);
                        }
                    }
                }
            }
        }
        sum = 0;
        for(int i =0 ;i < n; i++){
            for(int k= 0; k < m; k++){
                if(mp[i][k] == '*') sum ++;
            }
        }
        if(sum == MaxMatch() * 2){
            printf("YES\n");
        }else{
            printf("NO\n");
        }
    }
}
View Code

今天水了十多道图论题,脑袋好疼,虽然代码行数加起来也有一两千,但是都是水题,练了一天手速.....有了女朋友也不能放弃治疗啊..........

 

8.POJ 2724

题意:m个长度为n的2进制数,可能某一位是*代替(代表*=1和*=0都被包含了)。要求用最少的另外一些二进制数(也可以某一位被*代替)将原来的那些覆盖(且只能覆盖一次),且要求不能覆盖原本不存在的二进制数。

刚开始想直接对每个点连接连接大于这个点编号并且能够相连的,我以为这样就能保证连线不重复,但是,如果有1-2,2-3这样的连线的话2相当于被使用了两次,我犯的错误就是没有将点分成两部分。对二分图的理解有加深的一层,虽然是好久前就应该掌握的,希望亚洲区之前能过把图论弄得差不多。

这段时间有点浮躁焦虑,不想太多了,抱着失败的觉悟和奔向成功的目标再努力一次吧......

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
#include<map>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
map<int, int> mp;
const int maxa = 2222;
char str[maxa][11];
char chess[maxa][11];
int main(){
    int n, m;
    while(scanf("%d%d", &n, &m), n+m){
        mp.clear();
        int num_chess = 0;
        for(int i = 0;i < m; i++){
            scanf("%s", str[i]);
            int star = 0;
            for(int k =0;k < n; k++){
                if(str[i][k] == '*'){
                    star = 1;
                    str[i][k] = '0';
                    int aa = 0;
                    for(int j =0; j < n; j++){
                        chess[num_chess][j] = str[i][j];
                        aa = aa*2 + str[i][j] - '0';
                    }//num_chess++;

                    if(mp[aa] == 0){
                        mp[aa] = 1;
                        num_chess++;
                    }

                    str[i][k] = '1';
                    aa = 0;
                    for(int j =0; j < n; j++){
                        chess[num_chess][j] = str[i][j];
                        aa = aa*2 + str[i][j] - '0';
                    }//num_chess++;

                    if(mp[aa] == 0){
                        mp[aa] = 1;
                        num_chess++;
                    }
                    break;
                }
            }
            if(!star){
                int aa = 0;
                for(int j =0; j < n; j++){
                    chess[num_chess][j] = str[i][j];
                    aa = aa*2 + str[i][j] - '0';
                }//num_chess++;

                if(mp[aa] == 0){
                    mp[aa] = 1;
                    num_chess++;
                }
            }
        }
        for(int i = 0 ; i < num_chess; i++){
            g[i].clear();
        }
        /*for(int i =0; i < num_chess; i++){
            printf("%s\n", chess[i]);
        }*/
        for(int i = 0;i < num_chess; i++){
            for(int k = 0; k < num_chess; k++){
                int sum_def = 0;
                int ss =0;
                for(int j = 0; j < n; j++){
                    if(chess[i][j] == '1') ss++;
                    if(chess[i][j] != chess[k][j])
                    sum_def ++;
                }
                if(ss %2 ==1 && sum_def == 1){
                    g[i].push_back(k);
                }
            }
        }
        Nx = num_chess;
        printf("%d\n", num_chess -MaxMatch());
    }
}
View Code

    

9.POJ 3692

题意:已知班级有g个女孩和b个男孩,所有女生之间都相互认识,所有男生之间也相互认识,给出m对关系表示哪个女孩与哪个男孩认识。现在要选择一些学生来组成一个团,使得里面所有人都认识,求此团最大人数。

这个题只要将没有关系的两个人连线,求最大点独立集就好,最大点独立集的求法是总点数减去最大匹配数

//二分图匹配(Hopcroft-Carp的算法)。
/*
初始化:g[][]邻接矩阵

调用:res=MaxMatch();  Nx,Ny要初始化!!!

时间复杂大为 O(V^0.5 E)



适用于数据较大的二分匹配

需要queue头文件

********************************************** */
#include<iostream>
#include<string.h>
#include<queue>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN=3000;

const int INF=1<<28;

int Mx[MAXN],My[MAXN],Nx,Ny;
vector<int> g[MAXN];
int dx[MAXN],dy[MAXN],dis;

bool vst[MAXN];

bool searchP()

{

    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<Nx;i++)

        if(Mx[i]==-1)

        {

            Q.push(i);

            dx[i]=0;

        }

    while(!Q.empty())

    {

        int u=Q.front();

        Q.pop();

        if(dx[u]>dis)  break;

        for(int i = 0; i < g[u].size(); i++){
            int v = g[u][i];
            if(dy[v]==-1)

            {

                dy[v]=dx[u]+1;

                if(My[v]==-1)  dis=dy[v];

                else

                {

                    dx[My[v]]=dy[v]+1;

                    Q.push(My[v]);

                }

            }
        }

    }

    return dis!=INF;

}

bool DFS(int u)

{
    for(int i = 0; i < g[u].size(); i++){
        int v = g[u][i];
        if(!vst[v]&&dy[v]==dx[u]+1)

           {

               vst[v]=1;

               if(My[v]!=-1&&dy[v]==dis) continue;

               if(My[v]==-1||DFS(My[v]))

               {

                   My[v]=u;

                   Mx[u]=v;

                   return 1;

               }

           }
    }
    return 0;

}

int MaxMatch()

{

    int res=0;

    memset(Mx,-1,sizeof(Mx));

    memset(My,-1,sizeof(My));

    while(searchP())

    {

        memset(vst,0,sizeof(vst));

        for(int i=0;i<Nx;i++)

          if(Mx[i]==-1&&DFS(i))  res++;

    }

    return res;

}
const int maxa = 222;
int G[maxa][maxa];
int main(){
    int n, m, q;
    int cas = 1;
    while(scanf("%d%d%d", &n, &m, &q)!=EOF){
        if(n == 0 && m == 0 && q == 0) return 0;

        for(int i = 1; i <= n; i++){
            for(int k = 1; k <= m; k++){
                G[i][k] = 1;
            }
        }
        while(q--){
            int u, v;
            scanf("%d%d", &u, &v);
            G[u][v] = 0;
        }
        for(int i = 1;i <= n; i++){
            g[i].clear();
            for(int k = 1;k  <= m; k++){
                if(G[i][k]){
                    g[i].push_back(k);
                }
            }
        }
        Nx = n+1;
        printf("Case %d: %d\n",cas++,  n+m - MaxMatch());
    }
}
View Code

 

posted @ 2015-09-23 18:48  icodefive  阅读(227)  评论(0)    收藏  举报