ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

专题 二分图 + 网络流

2021-07-18 13:00:45  阅读:139  来源: 互联网

标签:二分 专题 fx int fy 网络 vis 505 dis


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

二分图相关概念:

(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;
}

 

标签:二分,专题,fx,int,fy,网络,vis,505,dis
来源: https://www.cnblogs.com/Chasing-Dreams-Z/p/14965277.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有