zoukankan      html  css  js  c++  java
  • 2018牛客网暑期ACM多校训练营(第五场) E

    题目链接:https://www.nowcoder.com/acm/contest/143/E

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 262144K,其他语言524288K
    64bit IO Format: %lld

    题目描述

    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.

    输入

    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个宿舍,4n个学生,即一个宿舍四个学生,学生从1~4n编号,

    第一年,每个宿舍x1[i],x2[i],x3[i],x4[i]代表四个学生,

    现在第二年,有n张表,每张表上y1,y2,y3,y4代表该宿舍四个学生分别想和谁一起住,

    现在需要决策每个学生住哪个宿舍,使得换宿舍的学生数最少,输出这个数。

    题解:

    转化为最小费用最大流解决的二分图问题,对每个去年的宿舍,向每个今年的组合连一条边,权值为1,费用为需要搬的人数(4-相同的人数),源点到去年各点,今年各点到汇点,都连一条权值为1费用为0的最大流,跑一次费用流即可。(参考https://www.nowcoder.com/discuss/90015?type=101&order=0&pos=1&page=0

    说实话,第一次看到这题比较懵逼的,因为以为宿舍必须住四个人,但是看了题解之后,发现好像没有规定宿舍住的人数。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=110;
    const int INF=0X3f3f3f3f;
    
    struct Edge{
        int u,v,c,f,a;
    };
    struct MCMF
    {
        int s,t;
        vector<Edge> E;
        vector<int> G[2*maxn];
        int vis[2*maxn];
        int d[2*maxn];
        int pre[2*maxn];
        int aug[2*maxn];
        void init(int l,int r)
        {
            for(int i=l;i<=r;i++) G[i].clear();
            E.clear();
        }
        void addedge(int from,int to,int cap,int cost)
        {
            E.push_back((Edge){from,to,cap,0,cost});
            E.push_back((Edge){to,from,0,0,-cost});
            int m=E.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
        bool SPFA(int s,int t,int &flow,int &cost)
        {
            memset(d,INF,sizeof(d));
            memset(vis,0,sizeof(vis));
            d[s]=0, vis[s]=1, pre[s]=0, aug[s]=INF;
            queue<int> q;
            q.push(s);
            while(!q.empty())
            {
                int now=q.front(); q.pop();
                vis[now]=0;
                for(int i=0;i<G[now].size();i++)
                {
                    Edge& e=E[G[now][i]];
                    int nex=e.v;
                    if(e.c>e.f && d[nex]>d[now]+e.a)
                    {
                        d[nex]=d[now]+e.a;
                        pre[nex]=G[now][i];
                        aug[nex]=min(aug[now],e.c-e.f);
                        if(!vis[nex])
                        {
                            q.push(nex);
                            vis[nex]=1;
                        }
                    }
                }
            }
            if(d[t]==INF) return 0;
            flow+=aug[t];
            cost+=d[t]*aug[t];
            for(int i=t;i!=s;i=E[pre[i]].u)
            {
                E[pre[i]].f+=aug[t];
                E[pre[i]^1].f-=aug[t];
            }
            return 1;
        }
    
        int mincost()
        {
            int flow=0,cost=0;
            while(SPFA(s,t,flow,cost));
            return cost;
        }
    }mcmf;
    
    int n;
    struct Dorm{
        int x[4];
    }fst[maxn],snd[maxn];
    int cost(Dorm fst,Dorm snd)
    {
        int res=4;
        for(int i=0;i<4;i++)
        {
            bool stay=0;
            for(int j=0;j<4;j++) stay|=(fst.x[i]==snd.x[j]);
            res-=stay;
        }
        return res;
    }
    
    int main()
    {
        scanf("%d",&n);
        mcmf.init(0,2*n+1);
        mcmf.s=0, mcmf.t=2*n+1;
    
        for(int i=1;i<=n;i++) for(int k=0;k<4;k++) scanf("%d",&fst[i].x[k]);
        for(int i=1;i<=n;i++) for(int k=0;k<4;k++) scanf("%d",&snd[i].x[k]);
    
        for(int i=1;i<=n;i++)
        {
            mcmf.addedge(mcmf.s,i,1,0);
            mcmf.addedge(n+i,mcmf.t,1,0);
            for(int j=1;j<=n;j++) mcmf.addedge(i,n+j,1,cost(fst[i],snd[j]));
        }
    
        printf("%d
    ",mcmf.mincost());
    }
  • 相关阅读:
    轻轻松松教你写日志-超级简单
    JAVA实现KNN分类
    怎样给filter加入自己定义接口
    设计模式之Visitor模式(笔记)
    Leet Code OJ 237. Delete Node in a Linked List [Difficulty: Easy]
    在C#中怎样推断线程当前所处的状态
    leetCode 83.Remove Duplicates from Sorted List(删除排序链表的反复) 解题思路和方法
    谈谈源码管理那点事儿(一)——源码管理十诫(转)
    安装gi的时候回退root.sh的运行
    Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验
  • 原文地址:https://www.cnblogs.com/dilthey/p/9420166.html
Copyright © 2011-2022 走看看