二分图的两种算法-最大匹配与最优匹配 poj--1469,2536

1.最大匹配
题目大意:给你p门课程和n个学生,一个学生可以选0门,1门,或者多门课 程,现在要求一个由p个学生组成的集合,满足下列2个条件:
(1).每个学生选择一个不同的课程
(2).每个课程都有不同的代表
如果满足,就输出YES

#include<cstdio>
#include<cstring>
using namespace std;
#define P 110
#define N 310
int map[P][N];
int match[N];
bool use[N];
int p, n;
bool find(int u) //u是课程
{
    for(int i = 1; i <= n; ++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 <= p; ++i) //统计匹配的课程
    {
        memset(use, false, sizeof(use));
        if(find(i))
            sumall++;
    }
    return sumall;
}
int main()
{
    int ncase;
    int stunum, temp, ans;
    scanf("%d", &ncase);
    while(ncase--)
    {
        memset(map, 0, sizeof(map));
        memset(match, -1, sizeof(match));
        scanf("%d%d", &p, &n);
        for(int i = 1; i <= p; ++i)
        {
            scanf("%d", &stunum);
            for(int j = 1; j <= stunum; ++j)
            {
                scanf("%d", &temp);
                map[i][temp] = 1; //temp号学生喜欢i号课程
            }
        }
        ans = sum();
        printf("%s\n", ans == p ? "YES" : "NO");
    }
    return 0;
}

2.最优匹配
题目大意:一块田地上有n只gopher和m个gopher洞,并且知道gopher的奔跑速度v。如果gopher的天敌出现,gopher不能在t时间内跑入一个洞内,就会有危险。每个洞只能住一只gopher,给出每个洞的坐标和每只gopher的坐标,问你天敌出现的时候,最少有几只gopher会有危险。

#include <stdio.h>
#include <string.h>
const int N = 105;
int n, m, s, v, link[N], vis[N], g[N][N];
double x1[N], y1[N], x2[N], y2[N], x;
bool dfs(int u)
{
    for (int i = 0; i < m; i++)
        if (!vis[i] && g[u][i])
        {
            vis[i] = 1;
            if (link[i] == -1 || dfs(link[i]))
            {
                link[i] = u;
                return true;
            }
        }
    return false;
}
int hungary()
{
    int res = 0;
    memset(link, -1, sizeof(link));
    for (int i = 0; i < n; i++)
    {
        memset(vis, 0, sizeof(vis));
        if (dfs(i))
            res++;
    }
    return res;
}
bool judge(int i, int j)
{
    if ((x1[i] - x2[j]) * (x1[i] - x2[j]) + (y1[i] - y2[j]) * (y1[i] - y2[j]) > x)
        return false;
    return true;
}
int main()
{
    while (~scanf("%d%d%d%d", &n, &m, &s, &v))
    {
        memset(g, 0, sizeof(g));
        x = s * v * s * v * 1.0;
        for (int i = 0; i < n; i++)
            scanf("%lf%lf", &x1[i], &y1[i]);
        for (int i = 0; i < m; i++)
            scanf("%lf%lf", &x2[i], &y2[i]);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (judge(i, j))
                    g[i][j] = 1;
        printf("%d\n", n - hungary());
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值