二分图及匹配的定义不介绍(还是那句话,网上有很多相关资料,说白了就是我懒)
匈牙利算法,总的来说就是对于每个点出发找增广路,找到一个非匹配点就连,如果找不到就去在增广路上抢别的点的匹配点,然后让别的点换地方。(网上还是有很多资料)
其实这篇文章我就是想来贴两道陈芝麻烂谷子的模板题。。。
https://www.luogu.org/problem/show?pid=3386 【模板】二分图匹配
这道题目不会的,应该去看所谓的“很多资料”。
题解:匈牙利算法(您略长、复杂度玄学的Dinic算法等也可)
代码:
#include
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;
}
来一道升级一点的模板
http://www.lydsy.com/JudgeOnline/problem.php?id=2663 [Beijing wc2012]灵魂宝石
R对K有单调性,所以可以二分。rmin直接跑最大匹配就行;rmax可以理解成求一个最小的极大匹配(不知道对不对),大概就是把分属于两个集合在原图中没有边的点在新图连边,有边的新图中不连边,然后用(n-最大匹配数)与k的大小关系作为判断的条件。大概是因为如果这样的匹配出来是k,说明对于当前的R,不可能有小于k的匹配满足条件,这样就能算出r的最大值。
代码:
#include
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;
}