专题 二分图 + 网络流

首先,二分图的问题都可以用网络流的相关知识解决,但是匈牙利算法也有不错的效果。

二分图相关概念:

(1)最大匹配数:用匈牙利算法可求得。

(2)最小点覆盖=最大匹配

(3)最小边覆盖=最大独立集=总节点数-最大匹配

1.【线性规划与网络流24题#24】骑士共存

专题 二分图 + 网络流

 

 专题 二分图 + 网络流

 

 solution:二分图板题,即求最大独立集,除了障碍其他的点与自己能够到达的点连边,跑最大匹配即可,最后用总格子数减去障碍数再减去最大匹配的一半即可。

2.[Ctsc2002]玩具兵

专题 二分图 + 网络流

 

 专题 二分图 + 网络流

 

 solution:暂时鸽了,贴个码,考察算法:二分图 + 最短路 + 二分。

#include <bits/stdc++.h>

using namespace std;

int dx[4] = {0, -1, 0, 1};
int dy[4] = {-1, 0, 1, 0};

typedef pair <int, int> P;

struct battle {
    int x, y;
}st[100005], des[2000005]; int m, n, k, t, ct, cnt, vis[505][505], cost[505][505], lk[500005], vvis[500005], dis[505][505], h[505][505];

bool check(int x, int y) {return x >= 1 && x <= m && y >= 1 && y <= n;} 

bool spfa(int s, int p)
{
    queue <P> Q;
    memset(dis, 0x3f, sizeof dis), memset(vis, 0, sizeof vis);
    dis[st[s].x][st[s].y] = 0; Q.push(make_pair(st[s].x, st[s].y));
    while (!Q.empty())
    {
        int x = Q.front().first, y = Q.front().second; Q.pop();
        vis[x][y] = 0;
        for (int i = 0; i < 4; i++)
        {
            int fx = x + dx[i], fy = y + dy[i], l = (p ^ (dis[x][y] & 1) ? h[x][y] < h[fx][fy] : h[x][y] > h[fx][fy]);
            if (check(fx, fy))
            {
                if (dis[fx][fy] > dis[x][y] + l)
                {
                    dis[fx][fy] = dis[x][y] + l;
                    if (!vis[fx][fy]) vis[fx][fy] = 1, Q.push(make_pair(fx, fy));
                }
            }
        }
    }
    for (int i = 1; i <= (k << 1 | 1); i++) cost[s][i] = dis[des[i].x][des[i].y];
}

bool find(int u, int lim)
{
    for (int v = 1; v <= 2 * k + 1; v++)
    {
        if ((vvis[v] ^ cnt) && cost[u][v] <= lim)
        {
            vvis[v] = cnt;
            if (!lk[v] || find(lk[v], lim)) return lk[v] = u, 1;
        }
    } return 0;
}

bool check(int lim)
{
    memset(vvis, 0, sizeof vvis), cnt = 0;
    memset(lk, 0, sizeof lk);
    int ans = 0;
    for (int i = 1; i <= (k << 1); i++) ++cnt, ans += find(i, lim);
    return ans + lim >= 2 * k;
}

int main()
{
    scanf("%d%d%d%d", &m, &n, &k, &t);
    for (int i = 1; i <= (k << 1 | 1); i++) scanf("%d%d", &st[i].x, &st[i].y);
    for (int i = 1, z; i <= t; i++)
    {
        scanf("%d%d%d", &des[i].x, &des[i].y, &z); --z;
        while (z--) ++ct, des[t + ct] = des[i];
    }
    for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) scanf("%d", &h[i][j]);
    for (int i = 1; i <= (k << 1); i++)
    {
        spfa(i, i > k);
    }
    int l = 0, r = 2 * k, mid, ans = 0;
    while (l <= r)
    {
        if (check(mid = l + r >> 1)) r = mid - 1, ans = mid;
        else l = mid + 1;
    } printf("%d", ans);
}

3.[HNOI2013 DAY1]消毒

专题 二分图 + 网络流

 

专题 二分图 + 网络流

 

 solution:暴力枚举最小一维的状态,将其强行转化为二维,于是转化为行列问题,可以用二分图解决。

#include <bits/stdc++.h>

using namespace std;

int x[500005], y[500005], z[500005], vis[500005], cnt;

int a, b, c, ok[500005];

struct node {
    int to, nxt;
}e[2000005]; int head[1000005], tot, lk[500005];
inline void add_e(int u, int v) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot;}

bool find(int u) {for (int i = head[u], v; i; i = e[i].nxt) if ((v = e[i].to) && (vis[v] ^ cnt) && (vis[v] = cnt) && (!lk[v] || find(lk[v])) && (lk[v] = u)) return 1; return 0;}

void solve()
{
    int minn = 0x3f3f3f3f, ans = 0x3f3f3f3f, ct = 0;
    scanf("%d%d%d", &a, &b, &c); minn = min(a, min(b, c));
    for (int i = 1; i <= a; i++) for (int j = 1; j <= b; j++) for (int k = 1, mm; k <= c; k++) 
    {
        scanf("%d", &mm);
        if (!mm) continue;
        x[++ct] = i, y[ct] = j, z[ct] = k;
    } if (minn == b) swap(a, b), swap(x, y);
    if (minn == c) swap(a, c), swap(x, z); int all = (1 << a) - 1;
    for (int s = 0; s <= all; s++) 
    {
        tot = 0, cnt = 0; int cost = 0;
        for (int i = 1; i <= b; i++) head[i] = vis[i] = lk[i] = 0;
        for (int i = 1; i <= a; i++)
        {
            if ((1 << (i - 1)) & s) ok[i] = 0, ++cost;
            else ok[i] = 1;
        }
        for (int i = 1; i <= ct; i++)
        {
            if (ok[x[i]]) add_e(y[i], z[i]);
        }
        for (int i = 1; i <= b; i++) ++cnt, cost += find(i);
        ans = min(ans, cost);
    }
    printf("%d\n", ans);
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--) solve();
    return 0;
}

 

上一篇:jq之事件


下一篇:Spring源码学习-自定义标签实践及原理