匈牙利算法模板(无算法讲解)

二分图最大匹配和匈牙利算法想学习知识点的误入

二分图及匹配的定义不介绍(还是那句话,网上有很多相关资料,说白了就是我懒

匈牙利算法,总的来说就是对于每个点出发找增广路,找到一个非匹配点就连,如果找不到就去在增广路上抢别的点的匹配点,然后让别的点换地方。(网上还是有很多资料


其实这篇文章我就是想来贴两道陈芝麻烂谷子的模板题。。。

模板题1

https://www.luogu.org/problem/show?pid=3386 【模板】二分图匹配

这道题目不会的,应该去看所谓的“很多资料”。

题解:匈牙利算法(您略长、复杂度玄学的Dinic算法等也可)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int cnt, head[N<<1], mth[N]; bool vis[N];
struct edge {int to, next;} e[N*N];
void addedge (int u, int v) {
    e[++cnt] = (edge){v, head[u]}; head[u] = cnt;
}
bool hgy (int x) {
    for (int i = head[x]; i; i = e[i].next)
        if (!vis[e[i].to]) {
            vis[e[i].to] = 1;
            if (!mth[e[i].to] || hgy (mth[e[i].to])) {
                mth[e[i].to] = x; return 1;
            }
        }
    return 0;
}
int main () {
    int n, m, ec, u, v, ans = 0;
    scanf ("%d%d%d", &n, &m, &ec);
    for (int i = 1; i <= ec; ++ i) {
        scanf ("%d%d", &u, &v);
        if (u<=n && v<=m) addedge (u, v);
    }
    for (int i = 1; i <= n; ++ i) {
        memset (vis, 0, sizeof (vis));
        if (hgy (i)) ++ ans;
    } printf ("%d\n", ans);
    return 0;
}

来一道升级一点的模板

模板题2

http://www.lydsy.com/JudgeOnline/problem.php?id=2663 [Beijing wc2012]灵魂宝石

R对K有单调性,所以可以二分。rmin直接跑最大匹配就行;rmax可以理解成求一个最小的极大匹配(不知道对不对),大概就是把分属于两个集合在原图中没有边的点在新图连边,有边的新图中不连边,然后用(n-最大匹配数)与k的大小关系作为判断的条件。大概是因为如果这样的匹配出来是k,说明对于当前的R,不可能有小于k的匹配满足条件,这样就能算出r的最大值。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef double DB;
const int N = 105;
const DB eps = 1e-8;
int head[N], cnt, n, k, mth[N];
bool vis[N];
struct edge {int to, next;} e[N*N];
struct point {int x, y;} a[N], b[N];
int cmp (DB a, DB b) {
    if (a-b>=0 && a-b<=eps) return 0;
    if (b-a>=0 && b-a<=eps) return 0;
    if (a-b>0) return 1; return -1;
}
int judis (point A, point B, DB d) {
    int dx = A.x-B.x, dy = A.y-B.y;
    DB dis = 1.0*dx*dx+dy*dy;
    return cmp (dis, d*d);
}
void addedge (int u, int v) {
    e[++cnt] = (edge){v, head[u]}; head[u] = cnt;
}
void init () {
    cnt = 0;
    memset (head, 0, sizeof (head));
    memset (mth, 0, sizeof (mth));
    for (int i = 1; i <= n*n; ++ i) {
        e[i].to = e[i].next = 0;
    }
}
bool hgy (int x) {
    for (int i = head[x]; i; i = e[i].next)
        if (!vis[e[i].to]) {
            vis[e[i].to] = 1;
            if (!mth[e[i].to] || hgy (mth[e[i].to])) {
                mth[e[i].to] = x; return 1;
            }
        }
    return 0;
}
bool Match (bool fl, DB r) {
    int ans = 0; init ();
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j) {
            if (fl && judis (a[i], b[j], r)<=0) addedge (i, j);
            if (!fl && judis (a[i], b[j], r)>=0) addedge (i, j);
        }
    for (int i = 1; i <= n; ++ i) {
        memset (vis, 0, sizeof (vis));
        if (hgy (i)) ++ ans; 
    }
    if (fl && ans>=k) return 1;
    if (!fl && ans>=n-k) return 1;
    return 0;
}
int main () {
    DB l, r, mid; scanf ("%d%d", &n, &k);
    for (int i = 1; i <= n; ++ i)
        scanf ("%d%d", &a[i].x, &a[i].y);
    for (int i = 1; i <= n; ++ i)
        scanf ("%d%d", &b[i].x, &b[i].y);
    l = 0, r = 1e6;
    for (int i = 1; i <= 45; ++ i) {
        mid = (l+r)/2;
        if (Match (1, mid)) r = mid;
        else l = mid;
    }
    printf ("%.2lf ", l);
    if (n==k) {puts ("+INF"); return 0;}
    l = 0, r = 1e6;
    for (int i = 1; i <= 45; ++ i) {
        mid = (l+r)/2;
        if (Match (0, mid)) l = mid;
        else r = mid;
    }
    printf ("%.2lf\n", l);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值