二分图匹配

A - 过山车

题目链接
在这里插入图片描述
在这里插入图片描述

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int N = 505;
int line[N][N];
int girl[N], used[N];
int k, m, n;
bool found(int x) {
    for (int i = 1; i <= n; i++) {
        if (line[x][i] && !used[i]) {
            used[i] = 1;
            if (girl[i] == 0 || found(girl[i])) {
                girl[i] = x;
                return 1;
            }
        }
    }
    return 0;
}
int main() {
    int x, y;
    while (scanf("%d", &k) && k) {
        scanf("%d %d", &m, &n);
        memset(line, 0, sizeof(line));
        memset(girl, 0, sizeof(girl));
        for (int i = 0; i < k; i++) {
            scanf("%d %d", &x, &y);
            line[x][y] = 1;
        }
        int sum = 0;
        for (int i = 1; i <= m; i++) {
            memset(used, 0, sizeof(used));
            if (found(i))
                sum++;
        }
        printf("%d\n", sum);
    }
    return 0;
}

题解:匈牙利算法的板子题

B - 50 years, 50 colors

题目链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
int n, k;
int a[110][110];
int col[60];
int book[110];
int match[110];
int newcol;
int dfs(int u) {
    for (int i = 1; i <= n; i++) {
        if (book[i] == 0 && a[u][i] == newcol) {
            book[i] = 1;
            if (match[i] == 0 || dfs(match[i])) {
                match[i] = u;
                return 1;
            }
        }
    }
    return 0;
}
int hungarian(int u) {
    newcol = u;  //记录当前颜色
    memset(match, 0, sizeof(match));
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        memset(book, 0, sizeof(book));
        if (dfs(i))
            ans++;
    }
    return ans;
}
int main() {
    while (~scanf("%d %d", &n, &k) && n + k) {
        memset(a, 0, sizeof(a));
        memset(col, 0, sizeof(col));
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &a[i][j]);
                col[a[i][j]]++;  //记录每个颜色出现的次数
            }
        }
        vector<int> v;
        for (int i = 1; i <= 50; i++) {
            if (col[i] > 0) {
                if (hungarian(i) > k) {
                    v.push_back(i);  //插入i
                }
            }
        }
        if (v.size() == 0)
            printf("-1\n");
        else {
            printf("%d", v[0]);
            for (int i = 1; i < v.size(); i++)
                printf(" %d", v[i]);
            printf("\n");
        }
    }
    return 0;
}

题解:二分图的最小点覆盖数(二分图的最大匹配)
行为左边,列为右边,对每种颜色判断这种颜色的气球最少需要多少次才能完全被扎破,尽可能的选出小的行号或列号,然后判断是否正好把所有颜色的气球都扎破了题解链接

C - Escape

题目链接
在这里插入图片描述
在这里插入图片描述

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
using namespace std;
int maps[100005][20];  //邻接矩阵
int vis[20];
int cy[20][100005];       //点集Y的匹配情况
int numy[20], limit[20];  // numy代表这个星球的匹配数量
int n, m;

int path(int u)  //找增广路
{
    int i, j;
    for (i = 0; i < m; i++) {
        if (maps[u][i] && !vis[i]) {
            vis[i] = 1;
            if (numy[i] < limit[i]) {
                cy[i][numy[i]++] = u;
                return 1;
            } else {
                for (j = 0; j < limit[i]; j++)
                    if (path(cy[i][j])) {
                        cy[i][j] = u;
                        return 1;
                    }
            }
        }
    }
    return 0;
}

int MulMatch()  //二分图多重匹配
{
    int ans = 0;
    memset(cy, 0, sizeof(cy));
    memset(numy, 0, sizeof(numy));
    for (int i = 0; i < n; i++) {
        memset(vis, 0, sizeof(vis));
        if (!path(i))
            return 0;
    }
    return 1;
}
int main() {
    int i, j, a;
    while (scanf("%d%d", &n, &m) != EOF) {
        memset(maps, 0, sizeof(maps));
        for (i = 0; i < n; i++)
            for (j = 0; j < m; j++)
                scanf("%d", &maps[i][j]);
        for (i = 0; i < m; i++)
            scanf("%d", &limit[i]);
        if (MulMatch())
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

题解:还是二分图匹配,只是要多加一个判断是否超过允许的链接数量限制题解链接

D - Necklace

题目链接
在这里插入图片描述
在这里插入图片描述

#include <stdlib.h>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 10;
int n, m, u, v, ans, pos[N], link[N];
bool s[N][N], vis[N];
vector<int> eg[N];
bool dfs(int u) {
    for (int i = 0; i < eg[u].size(); i++) {
        int v = eg[u][i];
        if (!vis[v]) {
            vis[v] = 1;
            if (link[v] == -1 || dfs(link[v])) {
                link[v] = u;
                return 1;
            }
        }
    }
    return 0;
}
void solve() {
    memset(s, 0, sizeof(s));
    while (m--) {
        scanf("%d%d", &u, &v);
        s[u][v] = 1;
    }
    ans = inf;
    for (int i = 1; i <= n; i++)
        pos[i] = i;
    do {
        memset(link, -1, sizeof(link));
        for (int i = 1; i <= n; i++) {
            eg[i].clear();
            for (int j = 1; j <= n; j++) {
                u = pos[i];
                if (i == 1)
                    v = pos[n];
                else
                    v = pos[i - 1];
                if (s[j][u] || s[j][v])
                    continue;
                eg[i].push_back(j);
            }
        }
        int now = 0;
        for (int i = 1; i <= n; i++) {
            memset(vis, 0, sizeof(vis));
            now += dfs(i);
        }
        ans = min(ans, n - now);
    } while (next_permutation(pos + 2, pos + n + 1) &&
             ans);  //一个柱子固定剩下(n-1)!的排列,因为是环!!
    printf("%d\n", ans);
}
int main() {
    while (~scanf("%d%d", &n, &m)) {
        if (!n) {
            puts("0");
            continue;
        }
        solve();
    }
    return 0;
}

题解:这里是二分图匹配,不过要先对阴球进行全排列,枚举所有可能出现的位置,因为是环,所以先固定一个位置,对其他位置进行枚举即可;因为阴球已经固定位置,所以剩下来就是用ed数组记录下阳球在阴球旁边不会变se的阳球号码;所以之后就是对可行的阳球进行二分匹配,把所有能安全放上去得阳球都放上去,然后用n一减就得出放上去会变色的阳球的数量。题解链接

E - Ants

题目链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题解:这里分为n个苹果树,n个蚁巢,要求一个蚁巢和一个苹果树之间形成一条路径,路径不能重复,苹果树和蚁巢只能用一次,路径的权值就是距离,求路径和最小。这题其实就是求二分图的最佳匹配,要用到km算法,是km算法的板子题。题解链接------算法链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值