車的放置 最大流求最大匹配

重点说一下二分图的两个部分,可以明确的是,車所在的一行一列不能再放置了,可以将这个位置,看作是車所在的行和列之间的连线,由此我们将行与列分开,可以看出,行的集合内部,没有连线,即没有哪一个車同时对多行起作用,同理,列也是如此,也就是说我们得到了一张二分图。如果某一个点不能放置,可以看作这一行和这一列之间没有边连接。然后根据这个建图,求最大匹配就是答案。

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 210, inf = 0x3f3f3f3f;
bool can[N][N];
int n, m, T;
int s, t;
int head[101000], nex[101000], to[101000], ed[101000], cnt;
void pre(){
    
    
    mem(can, true);
    s = 1000;
    t = 1001;
    cnt = 1;
    mem(head, -1);
    mem(nex, -1);
}
void add(int a, int b, int c){
    
    
    to[++cnt] = b, nex[cnt] = head[a], head[a] = cnt, ed[cnt] = c;
    to[++cnt] = a, nex[cnt] = head[b], head[b] = cnt, ed[cnt] = 0;
}
int d[101000], cur[101000];
bool bfs(){
    
    
    queue<int > q;
    cur[s] = head[s];
    cur[t] = head[t];
    for (int i = 1; i <= n; i++)cur[i] = head[i];
    for (int i = 1; i <= m; i++)cur[i + 210] = head[i + 210];
    q.push(s);
    mem(d, 0);
    d[s] = 1;
    while (q.size()){
    
    
        int tp = q.front();
        q.pop();
        for (int i = head[tp]; ~i; i = nex[i]){
    
    
            if (!d[to[i]] && ed[i]){
    
    
                d[to[i]] = d[tp] + 1;
                q.push(to[i]);
                if (to[i] == t)return 1;
            }
        }
    }
    return 0;
}
int dinic(int x, int f){
    
    
    if (x == t || f == 0)return f;
    int flow = 0;
    int k;
    for (int i = cur[x]; ~i; i = nex[i]){
    
    
        cur[x] = i;
        int y = to[i];
        if (d[y] == d[x] + 1 && ed[i]){
    
    
            k = dinic(y, min(f, ed[i]));
            if (!k){
    
    
                d[y] = 0;
            }
            ed[i] -= k;
            ed[i ^ 1] += k;
            flow += k;
            if (f - flow == 0)break;
        }
    }
    return flow;
}
int maxflow(){
    
    
    int f = 0;
    while (bfs()){
    
    
        f += dinic(s, inf);
    }
    return f;
}
int main(){
    
    
    ios::sync_with_stdio(false);
    pre();
    cin >> n >> m >> T;
    while (T--){
    
    
        int x, y;
        cin >> x >> y;
        can[x][y] = 0;
    }
    // 行 和 列 是二分图的两部分
    for (int i = 1; i <= n; i++){
    
    
        add(s, i, 1);
        for (int j = 1; j <= m; j++){
    
    
            if (can[i][j]){
    
    
                add(i, j + 210, 1);
            }
        }
    }
    for (int i = 1; i <= m; i++)add(i + 210, t, 1);
    cout << maxflow() << "\n";
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/108111654
今日推荐