二分图匹配

ZOJ3037 稳定婚姻问题

白书353页 挺有意思

//550ms

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
#define N 1010
int male_choice[N][N];
int female_rank[N][N];
int fwife[N],fhusb[N];
int next_girl[N];
queue<int>q;
void engage(int man,int woman)
{
    if(fhusb[woman])
    {
        fwife[fhusb[woman]]=0;
        q.push(fhusb[woman]);
    }
    fwife[man]=woman;
    fhusb[woman]=man;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&male_choice[i][j]);
            }
            q.push(i);
            next_girl[i]=1;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int x;
                scanf("%d",&x);
                female_rank[i][x]=j;
            }
        }
        memset(fwife,0,sizeof(fwife));
        memset(fhusb,0,sizeof(fhusb));
        while(!q.empty())
        {
            int man=q.front();q.pop();
            int woman=male_choice[man][next_girl[man]++];
            if(!fhusb[woman]){
                engage(man,woman);
            }
            else if(female_rank[woman][man]<female_rank[woman][fhusb[woman]])
            {
                engage(man,woman);
            }
            else q.push(man);
        }
        for(int i=1;i<=n;i++)
        {
            printf("%d\n",fwife[i]);
        }

    }
}



二分图系统学习

http://blog.csdn.net/hackbuteer1/article/details/7398008

趣写算法系列之--匈牙利算法

http://blog.csdn.net/dark_scope/article/details/8880547

二分图模板:

模板一:匈牙利算法

POJ1469 500ms

#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
/* **************************************************************************
//二分图匹配(匈牙利算法的DFS实现)
//初始化:g[][]两边顶点的划分情况
//建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配
//g没有边相连则初始化为0
//uN是匹配左边的顶点数,vN是匹配右边的顶点数
//调用:res=hungary();输出最大匹配数
//优点:适用于稠密图,DFS找增广路,实现简洁易于理解
//时间复杂度:O(VE)
//顶点编号从1开始的
//***************************************************************************/

const int MAXN=510;
int uN,vN;//u,v数目
int g[MAXN][MAXN];
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)//从左边开始找增广路径
{
    int v;
    for(v=1;v<=vN;v++)//这个顶点编号从0开始,若要从1开始需要修改
      if(g[u][v]&&!used[v])
      {
          used[v]=true;
          if(linker[v]==-1||dfs(linker[v]))
          {//找增广路,反向
              linker[v]=u;
              return true;
          }
      }
    return false;//这个不要忘了,经常忘记这句
}
int hungary()
{
    int res=0;
    int u;
    memset(linker,-1,sizeof(linker));
    for(u=1;u<=uN;u++)//这个顶点编号从0开始,若要从1开始需要修改
    {
        memset(used,0,sizeof(used));
        if(dfs(u)) res++;
    }
    return res;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(g,0,sizeof(g));
        scanf("%d%d",&uN,&vN);
        for(int i=1;i<=uN;i++)
        {

            int k,x;
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&x);
                g[i][x]=1;
            }
        }

        int ans=hungary();
        if(ans==uN)printf("YES\n");
        else printf("NO\n");
    }

    return 0;
}

最大独立集

求二分图的最大独立点集 , 用匈牙利算法先求出最大匹配数 , 然后用总数减去最大匹配数就是题目要求的答案 .邻接表写法:

zoj1137

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#define N 550
#define INF 99999999
int n;
vector<int>g[N];
int linker[N];
bool used[N];
bool dfs(int u)
{
    int v;
    for(int i=0;i<g[u].size();i++)
    {
        v=g[u][i];
        if(!used[v])
        {
            used[v]=true;
            if(linker[v]==-1||dfs(linker[v]))
            {
                linker[v]=u;
                return true;
            }
        }
    }
    return false;//这个不要忘了,经常忘记这句 
}
int hungary()
{
    int res=0;
    memset(linker,-1,sizeof(linker));
    for(int i=0;i<n;i++)
    {
        memset(used,0,sizeof(used));
        if(dfs(i))res++;
    }
    return res;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)g[i].clear();
        for(int i=0;i<n;i++)
        {
            int a,k,b;
            scanf("%d: (%d)",&a,&k);
            while(k--)
            {
                scanf("%d",&b);
                g[a].push_back(b);
            }
        }
        int ans=hungary();
        printf("%d\n",n-ans/2);
    }

    return 0;
}



模板二:Hopcroft-Carp算法

这个算法比匈牙利算法的时间复杂度要小,大数据可以采用这个算法

//poj_1469
/*==================================================*\
| 二分图匹配(Hopcroft-Carp 的算法)
| INIT: g[][]邻接矩阵;
| CALL: res = MaxMatch(); Nx, Ny要初始化!!!
| Mx,My为match
| 时间复杂度为O(V^0.5 E)
\*==================================================*/
/***********************Hopcroft-Carp 算法****************************************/
#include <cstdio>
#include <memory.h>
#include <queue>
using namespace std;

const int MAXN = 310;
const int INF = 1 << 28;
bool flag;
int p,n;
int  Mx[MAXN], My[MAXN], Nx, Ny;
int dx[MAXN], dy[MAXN], dis;
bool vst[MAXN],g[110][310];
bool searchP(void)
{
    queue <int> Q;
    dis = INF;
    memset(dx, -1, sizeof(dx));
    memset(dy, -1, sizeof(dy));
    for (int i = 1; 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 = 1; 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 = 1; v <= Ny; v++)
    if (!vst[v] && g[u][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(void){
    int res = 0;
    memset(Mx, -1, sizeof(Mx));
    memset(My, -1, sizeof(My));
    while (searchP()) {
          memset(vst, 0, sizeof(vst));
          for (int i = 1; i <= Nx; i++)
              if (Mx[i] == -1 && DFS(i)) res++;
    }
    return res;
}

/**********************************************************************/
int main()
{
    int i,j,k,t,v,cnt;
    scanf("%d",&t);
    while (t--)
    {
          scanf("%d %d", &p, &n);
          for (i = 1; i <= p; i++)
              for (j = 1; j <= n; j++)
                  g[i][j] = false;
          flag = true;
          for (i = 1; i <= p; i++)
          {
              scanf("%d",&k);
              if (k == 0)
                 flag = false;
              while (k--)
              {
                    scanf("%d",&v);
                    g[i][v]  = true;
              }
          }
          Nx = p; Ny = n;
          if (flag)
          {
               cnt = MaxMatch();
               if (cnt == p)
                  printf("YES\n");
               else printf("NO\n");   
          } 
          else printf("NO\n"); 
    }
    
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值