room——费用流

这是一篇关于如何利用费用流算法解决一个学生宿舍分配问题的博客。在Nowcoder University,四年级的学生需要重新决定宿舍室友,目标是最小化更换宿舍的学生数量。题目描述中提供了输入和输出的具体格式,并给出了一种暴力枚举失败的尝试。作者指出,正确解决方案是应用费用流算法,通过设定宿舍间的流量限制和费用,以最小化总费用来确定学生宿舍分配。
摘要由CSDN通过智能技术生成

链接: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与n的宿舍限定流量是1,费用是两个宿舍不一样的人的个数,进行建边,然后跑一遍最小费用流。(比赛时想不到啊。虽然赛后也是仔细想了想才知道的)

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
 
using namespace std;
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const ll mod=1e9+7;
const double eps=1e-5;
const int maxm=1e2+10,maxn=5e4+7;
int T,k,m,n,N;
 
struct Edge{
    int to,next,cap,flow,cost;
}edge[maxn];
int tol,head[maxn],pre[maxn],dis[maxn];
bool vis[maxn];
void init()
{
    tol=0,mem(head,-1);
}
void addedge(int u,int v,int cap,int cost)
{
    edge[tol].to=v;edge[tol].cap=cap;edge[tol].cost=cost;
    edge[tol].flow=0;edge[tol].next=head[u];head[u]=tol++;
    edge[tol].to=u;edge[tol].cap=0;edge[tol].cost=-cost;
    edge[tol].next=head[v];edge[tol].flow=0;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;i=edge[i].next){
            int v=edge[i].to;
            if(edge[i].cap>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;
    return true;
}
int mincostmaxflow(int s,int t,int &cost)
{
    int flow=0;
    cost=0;
    while(spfa(s,t)){
        int Min=INF;
        for(int i=pre[t];~i;i=pre[edge[i^1].to])
            if(Min>edge[i].cap-edge[i].flow)
                Min=edge[i].cap-edge[i].flow;
        for(int i=pre[t];~i;i=pre[edge[i^1].to])
            edge[i].flow+=Min,edge[i^1].flow-=Min,cost+=edge[i].cost*Min;
        flow+=Min;
    }
    return flow;
}
 
struct node{
    int num[4];
};
node a[maxn],b[maxn];
 
int main()
{
    scanf("%d",&n);
    init();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<4;j++){
            scanf("%d",&a[i].num[j]);
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<4;j++){
            scanf("%d",&b[i].num[j]);
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            int v=0;
            for(int k=0;k<4;k++)
            {
                for(int p=0;p<4;p++)
                {
                    if(a[i].num[k]==b[j].num[p]) 
                        v++;
                    addedge(i+1,n+j+1,1,4-v);
                }
            }
        }
    }
    for(int i=0;i<n;i++)
        addedge(0,i+1,1,1),addedge(n+i+1,n*2+1,1,1);
    int ans;
    N=n*2+2;
    mincostmaxflow(0,n*2+1,ans);
    printf("%d\n",ans-n*2);
 
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值