牛客网暑期ACM多校训练营(第五场) E room(最小费用最大流 , 最小权二分图匹配模板)

链接:

https://www.nowcoder.com/acm/contest/143/E

题意:

给定n个宿舍的新安排, 每个宿舍都有4个人, 问要至少有多少个人换位才能变成新安排。

可以建一个二分图, 左边n个点为原来的安排, 右边n个点为新安排,  每条边花费设为( 4 - 交集), 然后跑费用流。

#include<bits/stdc++.h>
using namespace std;
const int maxN = 300;
const int maxM = 1e5 + 7;
const int INF = 1e9 + 7;
int n, ecnt, S, T;
struct {
    int to, w, cost, nxt;
} edge[maxM];
 
struct Node{
    int v, id;
}pre[maxN];
int head[maxN];
int bef[maxN][4], after[maxN][4];
 
 
void init() {
    memset(head, -1, sizeof(head));
    ecnt = 0;
}
void addEdge(int u, int v, int w, int c) {
    edge[ecnt].to = v;
    edge[ecnt].w = w;
    edge[ecnt].cost = c;
    edge[ecnt].nxt = head[u];
    head[u] = ecnt++;
}
inline int dif(int a, int b) {
    int res = 4;
    for(int i = 0; i < 4; i++) {
        for(int j = 0; j < 4; j++) {
            if(bef[a][i] == after[b][j]) {
                res--;
                break;
            }
        }
    }
    return res;
}
void build() {
    S = 0, T = 2 * n + 1;
 
    for(int i = 1; i <= n; i++) {
        addEdge(S, i, 1, 0);
        addEdge(i, S, 0, 0);
        addEdge(i + n, T, 1, 0);
        addEdge(T, i + n, 0, 0);
    }
 
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            int c = dif(i, j);
            addEdge(i, j + n, 1, c);
            addEdge(j + n, i, 0, -c); //建反向边的时候注意花费要为负
        }
    }
}
int vis[maxN], cost[maxN];
bool spfa(){
    queue<int> q;
    memset(vis, 0, sizeof(vis));
    fill(cost ,cost + maxN, INF);
    vis[S] = 1;
    cost[S] = 0;
    q.push(S);
    while(!q.empty()){
        int u = q.front();
        for(int i = head[u]; i != -1; i = edge[i].nxt){
            int v = edge[i].to, f = edge[i].w , c = edge[i].cost;
            if(f == 0 || cost[v] <= cost[u] + c) continue;
            cost[v] = cost[u] + c;
            pre[v].v = u;
            pre[v].id = i;
            if(!vis[v]){
                q.push(v);
                vis[v] = true;
            }
        }
        vis[u] = 0;
        q.pop();
    }
    return cost[T] != INF;
}
int MCMF(){
    int flow = 0;
    int minCost = 0;
    while(spfa()){
        int minFlow = INF;
        for(int i = T; i != S; i = pre[i].v){
            minFlow = min(minFlow, edge[pre[i].id].w);
        }
        for(int i = T; i != S; i = pre[i].v){
            edge[pre[i].id].w -= minFlow;
            edge[pre[i].id ^ 1].w += minFlow;
        }
        minCost += cost[T];
    }
    return minCost;
}
int main() {
//    freopen("1.txt","r", stdin);
    ios::sync_with_stdio(false);
 
    cin >> n;
    init();
    for(int i = 1; i <= n; i++)
        for(int j = 0; j < 4; j++)
            cin >> bef[i][j];
 
 
    for(int i = 1; i <= n; i++)
        for(int j = 0; j < 4; j++)
            cin >> after[i][j];
 
    build();
    cout << MCMF() << "
";
}
原文地址:https://www.cnblogs.com/Jadon97/p/9426420.html