• 最小费用最大流


    链接:https://www.nowcoder.com/acm/contest/143/E
    来源:牛客网

    题目描述

    Nowcoder University has 4n students and n dormitories ( Four students per dormitory). Students numbered from 1 to 4n.

    And in the first year, the i-th dormitory 's students are (x1[i],x2[i],x3[i],x4[i]), now in the second year, Students need to decide who to live with.

    In the second year, you get n tables such as (y1,y2,y3,y4) denote these four students want to live together.

    Now you need to decide which dormitory everyone lives in to minimize the number of students who change dormitory.

    输入描述:

    The first line has one integer n.

    Then there are n lines, each line has four integers (x1,x2,x3,x4) denote these four students live together in the first year

    Then there are n lines, each line has four integers (y1,y2,y3,y4) denote these four students want to live together in the second year

    输出描述:

    Output the least number of students need to change dormitory.
    示例1

    输入

    复制
    2
    1 2 3 4
    5 6 7 8
    4 6 7 8
    1 2 3 5

    输出

    复制
    2

    说明

    Just swap 4 and 5

    备注:

    1<=n<=100

    1<=x1,x2,x3,x4,y1,y2,y3,y4<=4n

    It's guaranteed that no student will live in more than one dormitories.

    题意 : 给你 n 间宿舍第一年的成员分配情况,再给你第二年所有人想住哪个寝室的分配情况,询问你最小让几个人搬寝室可以达成要求?
    思路分析:网络流建图,跑个费用流即可
    重点是怎么建图,考虑第二年宿舍的分配情况,去分别匹配第一年的所有宿舍,去计算每种情况需要更换几个人,即为费用,流量是 1
    代码示例 :
    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e4;
    const int maxm = 1e5;
    const int inf = 0x3f3f3f3f;
    struct Edge
    {
        int to,next,flow,cost; // flow 表示水现有的流量
    }edge[maxm];
    int head[maxn],tol;
    int pre[maxn],dis[maxn];
    bool vis[maxn];
    int N; //节点个数,编号0->N-1 !全局变量 需要init赋值或主函数改变
    
    void init(int n)
    {
        N=n;
        tol = 0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v,int cap,int cost) //边起点,终点,流量,费用
    {
        edge[tol].to = v;
        edge[tol].cost = cost;
        edge[tol].flow = cap;
        edge[tol].next = head[u];
        head[u] = tol++;
        edge[tol].to = u;
        edge[tol].cost = -cost;
        edge[tol].flow = 0;
        edge[tol].next = head[v];
        head[v] = tol++;
    }
    
    bool spfa(int s,int t)     //单源最短路径算法 可判断负环
    {
        queue<int >q;
        for(int i=0;i<N;i++)
        {
            dis[i] = inf;
            vis[i] = false;
            pre[i] = -1;
        }
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v= edge[i].to;
                if(edge[i].flow && dis[v]>dis[u]+edge[i].cost)
                {
                    dis[v] = dis[u] + edge[i].cost;
                    pre[v] = i;
                    if(!vis[v])
                    {
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t]==-1) return false;
        else return true;
    }
    
    int MCMF(int s,int t,int &cost)  //MinCostMaxFlow  返回最大流,cost存最小费用
    {
        int flow = 0;
        cost = 0;
        while(spfa(s,t))
        {
            int Min = inf;
            for(int i= pre[t];i!=-1;i=pre[edge[i^1].to])
            {
                if(Min>edge[i].flow)
                    Min=edge[i].flow;
            }
            for(int i= pre[t];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow -= Min;
                edge[i^1].flow +=Min;
                cost += edge[i].cost*Min;
            }
            flow += Min;
        }
        return flow;
    }
    
    int n;
    struct node{
        int a, b, c, d;
    }arr[205];
    
    int fun(int x, int y){
        int res = 4;
        if (arr[x].a==arr[y].a || arr[x].a==arr[y].b || arr[x].a==arr[y].c || arr[x].a==arr[y].d) res--;
        if (arr[x].b==arr[y].a || arr[x].b==arr[y].b || arr[x].b==arr[y].c || arr[x].b==arr[y].d) res--;
        if (arr[x].c==arr[y].a || arr[x].c==arr[y].b || arr[x].c==arr[y].c || arr[x].c==arr[y].d) res--;
        if (arr[x].d==arr[y].a || arr[x].d==arr[y].b || arr[x].d==arr[y].c || arr[x].d==arr[y].d) res--; 
    
        return res;
    }
    
    int main() {
        
        cin >> n;
        for(int i = 1; i <= 2*n; i++){
            scanf("%d%d%d%d", &arr[i].a, &arr[i].b, &arr[i].c, &arr[i].d);
        }
        init(2*n+2);
        for(int i = 1; i <= n; i++){
            addedge(0, i, 1, 0);
            addedge(n+i, 2*n+1, 1, 0);
            for(int j = n+1; j <= 2*n; j++){
                addedge(i, j, 1, fun(i, j));
            }
        }
        int ans;
        MCMF(0, 2*n+1, ans);
        printf("%d
    ", ans);
        return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    JS单例对象与构造函数对象的区别
    SVG系列
    Js极客之路
    Js极客之路
    iOS微信登录
    iOS HSV
    cocoa pods
    php中请求数据中文乱码
    付费中数字计算
    时间戳对应关系
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/9433616.html
Copyright © 2020-2023  润新知