hoj 2524 Allocate Dormitories 二分图的最大匹配

 

/*

 

题目:

 

    哈工大推出新的宿舍分配方案,当两人对A B题有相同答案的人可以分在A类宿舍,

 

    C D题有相同答案的人可以分在B类宿舍,每一间的宿舍人数没有限制的话,问可

 

    以最少要分配多少间宿舍才能分好所有学生

 

分析:

 

    每一个学生都可以分配在A类宿舍i,或者B类宿舍j,因此,g[i][j] = true,由此可以

 

    构造一个二分图,用hungry算法做

 

    由于输入的数据比较大,若用两层循环判断的话,会超时,所以可以先排序,然后再判断

 

    与前面的一不一样,若一样则置g[i][j] = true,i j的值需要先处理好,具体看代码

 

*/

 

#include <iostream>

 

#include <cstring>

 

#include <cstdio>

 

#include <algorithm>

 

using namespace std;

 

#define X 102

 

int ym[X],na,nb;

 

bool g[X][X],use[X];

 

struct node

 

{

 

       int a,b,c,d;

 

       int na,nb;                    //所在的宿舍A B的房间号

 

}p[X*X];

 

bool cmp1(node a,node b)//对前两个关键字排序

 

{

 

       if(a.a==b.a)

 

              return a.b<b.b;

 

       else

 

              return a.a<b.a;

 

}

 

bool cmp2(node a,node b)//对后两个关键字进行排序

 

{

 

       if(a.c==b.c)

 

              return a.d<b.d;

 

       else

 

              return a.c<b.c;

 

}

 

bool dfs(int u)//寻找一条增广路

 

{

 

       int t;

 

       for(int v=1;v<=nb;v++)

 

              if(g[u][v]&&!use[v])

 

              {

 

                     use[v] = true;

 

                     t = ym[v];

 

                     ym[v] = u;    //路径取反操作

 

                     if(t==-1||dfs(t))//寻找是否为增广轨

 

                            return true;

 

                     ym[v] = t;

 

              }

 

              return false;

 

}

 

int hungry()  //

 

{

 

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

 

       int ret = 0;                  //初始时增广轨为空

 

       for(int u=1;u<=na;u++)//从二分图的左部的每个顶点开始寻找增广轨

 

       {

 

              memset(use,false,sizeof(use));

 

              if(dfs(u))                    //若找到,把它取反,总匹配加一

 

                     ret++;

 

       }

 

       return ret;                          //返回最大匹配数

 

}

 

int main()

 

{

 

       freopen("sum.in","r",stdin);

 

       freopen("sum.out","w",stdout);

 

       int n,t;

 

       scanf("%d",&t);

 

       while(t--)

 

       {

 

              scanf("%d",&n);

 

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

 

                     scanf("%d%d%d%d",&p[i].a,&p[i].b,&p[i].c,&p[i].d);

 

              sort(p,p+n,cmp1);

 

              na = nb = 1;

 

              p[0].na = p[0].nb = 1;

 

              int ta = p[0].a,tb = p[0].b;

 

              for(int i=1;i<n;i++)            //A型宿舍进行标号

 

              {

 

                     if(p[i].a==ta&&p[i].b==tb)      //如果与前面的一样的话,在A型宿舍的位置与当前的B型宿舍总数一样

 

                            p[i].na = na;

 

                     else                                    //否则,B型宿舍总数加一

 

                     {

 

                            p[i].na = ++na;

 

                            ta = p[i].a;                   //更新

 

                            tb = p[i].b;

 

                     }

 

              }

 

              memset(g,false,sizeof(g));

 

              sort(p,p+n,cmp2);       //对后两个关键字进行排序

 

              int tc = p[0].c,td = p[0].d;

 

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

 

              {

 

                     if(p[i].c==tc&&p[i].d==td)      //如果与前面的一样的话,在B型宿舍的位置与当前的B型宿舍总数一样

 

                            p[i].nb = nb;

 

                     else                                    //否则,B型宿舍总数加一

 

                     {

 

                            p[i].nb = ++nb;

 

                            tc = p[i].c;                   //更新

 

                            td = p[i].d;

 

                     }

 

                     g[p[i].na][p[i].nb] = true;//相当于A型宿舍iB型宿舍j相连

 

              }

 

              printf("%d\n",hungry());

 

       }

 

       return 0;

 

}

 

 

 

转载于:https://www.cnblogs.com/yejinru/archive/2012/04/07/2436078.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值