caioj 1123 上课(二分图匹配)

题目描述
(看完题意,你将要假设什么是公牛,什么是母牛,~~~)
一个星期有7天,每天有12节课。
有n门课程,但是有些课程上课的时间是冲突的,
求最多能上多少门课程。
Input
第一行为整数 n (1 <= n <= 300), 表示课程的总数。下来n行表示n门课程的信息。每行第一个数为整数 t (1 <= t <= 7*12), 表示学生可以学习该门课程的时间段总数。下来t对整数,每对整数为 p (1 <= p <= 7) and q (1 <= q <= 12), 表示该门课程在每个星期的第p天的第q节课上课。
Output
输出一行,最多能上多少门课。

Sample Input
5
1 1 1
2 1 1 2 2
1 2 2
2 3 2 3 3
1 3 3

Sample Output
4

这是一道二分图匹配的题,但是要转化模型,思考一下就可以看出要匹配的应该是课程n与上课时间。然后就是一道模板题了。
但是在写代码的时候就会发现一个问题就是课程n与上课的时间如何进行匹配储存。我这里是用一个二维的数组分别存课程与时间的。然后在dfs函数里面加个参数,1为课程,2为时间,在搜索时候比较容易转化。
这是我的代码:
    #include<cstdio>
#include<vector>
#include<cstring>
#define maxn 307

using namespace std;

vector<int> lesson[maxn][3];
int match[maxn][3];
int n;
bool check[maxn][3];
int ans;

bool dfs(int z,int y)
{
     int c=lesson[z][y].size();
     int p;
     if(y==1)p=2;
     if(y==2)p=1;
     for(int i=0;i<c;i++)
     {
         int v=lesson[z][y][i];
         if(!check[v][y])
         {
             if(match[v][y]==0||dfs(match[v]))
             {
                 match[v][y]=z;
                 match[z][y]=v;
                 return true;
             }
         }
     }
     return false;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int h;scanf("%d",&h);
        for(int j=1;j<=h;j++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            lesson[i][1].push_back(x*12+y);
            lesson[x*12+y][2].push_back(n);
        }
    }
    for(int i=1;i<=n;i++)
    (
        if(!match[n][1])
        {
        memset(check,0,sizeof(check));
        if(dfs(n,1))ans++;
        }
    )
    printf("%d\n",ans);
    return 0;
}
我用邻接表做比较麻烦,用链式前向星就比较简单了,别人的代码:
    #include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<vector>  
#include<algorithm>  
using namespace std;  
#define N 310  
int soursenum;  
int map[N][90];  
int match[N];  
bool use[N];  

bool find(int u) //查询匹配的课程  
{  
    for(int i = 1; i <= 84; ++i)  
    {  
        if(!use[i] && map[u][i])  
        {  
            use[i] = true;  
            if(match[i] == -1 || find(match[i]))  
            {  
                match[i] = u;  
                return true;  
            }  
        }  
    }  
    return false;  
}  

int sum()  
{  
    int sumall = 0;  
    for(int i = 1; i <= soursenum; ++i)  
    {  
        memset(use, false, sizeof(use));  
        if(find(i))  
            sumall++;  
    }  
    return sumall;  
}  

int main()  
{  
    int everynum;  
    int day, time;  
    while(scanf("%d", &soursenum) != EOF)  
    {  
        memset(map, 0, sizeof(map));  
        memset(match, -1, sizeof(match));  
        for(int k = 1; k <= soursenum; ++k)  
        {  
            scanf("%d", &everynum);  
            for(int i = 1; i <= everynum; ++i)  
            {  
                scanf("%d%d", &day, &time);  
                map[k][(day - 1) * 12 + time] = 1; //巧妙转换  
            }  
        }  
        printf("%d\n", sum());  
    }  
    return 0;  
}    

是时候学一下链式前向星了,哈哈哈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值