hdu 2444

二分图的判断以及二分图的最大匹配


题意:给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识;

现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多大?


首先,利用交叉染色法判断一个图是否为二分图。。。

用DFS就可;取任意点,标记,搜索与其有边的点,如果该点没有被标记,则将其标记为相反,继续向下搜索;如果被标记了,则判断其标记与应该被标记的值是否一致,一致则继续,不一致则判断该图不是二分图。


然后,则是二分图的最大匹配的计算;

建立一张二分图,左右两边都是图的所有节点;

取左端节点,依次向下判断是否在右端存在节点与其相连;

每次判断时,如果节点的右端相连的节点已经存在左端的节点与之相连,则判断该左端节点是否还有另外的节点可以与之相连,依次递归的向下推;


代码:

#include<iostream>
#include<vector>
using namespace std;
vector <int> ver[1000];
int exist[1000];
int havever[1000];
int flag[1000];
int n,m;
int DFS(int start,int cer){
    for(int i=ver[start].size()-1;i>=0;i--){
                 if(!flag[ver[start][i]]){
                       flag[ver[start][i]]=-cer;
                       if(!DFS(ver[start][i],-cer))
                             return false;
                 }
                 else{
                      if(flag[ver[start][i]]==cer){
                           return false;
                      }
                 }
    }
    return true;
}
bool ishalf(){
     memset(flag,0,sizeof(flag));
     flag[1]=1;
     if(DFS(1,1))
          return true;
     return false;     
}
bool able(int start){
     for(int k=ver[start].size()-1;k>=0;k--){
             int temp=ver[start][k];
             if(exist[temp]==-1){
                    exist[temp]=1;
                    if(havever[temp]==-1||able(havever[temp])){
                           havever[temp]=start;
                           return true;
                    }
             }
     }
     return false;
}
int find(){
    int sum=0;
    memset(havever,-1,sizeof(havever));
    for(int j=1;j<=n;j++){
            memset(exist,-1,sizeof(exist));
            if(able(j))
                sum++;   
    }
    return sum;
}
int main(){
 //   int n,m;
    while(cin>>n>>m){
         for(int i=0;i<=n;i++){
                 ver[i].clear();
         }
         for(int i=0;i<m;i++){
                 int temp1,temp2;
                 cin>>temp1>>temp2;
                 ver[temp1].push_back(temp2);
                 ver[temp2].push_back(temp1);
         }
         bool res=ishalf();
         if(!res){
             cout<<"No"<<endl;
             continue;
         }
         int times=find();
         cout<<times/2<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值