牛客网暑期ACM多校训练营(第五场)E room KM 带权匹配 or 最大流

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

room

时间限制: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.

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

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

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

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

思路:KM模板题,g[][]建图直接根据两个寝室之间的相同人数作为权值跑最大权匹配,最后求出的答案ans表示最多有多少人不用换寝室,然后总人数4*n减去最大全匹配就是答案。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=205;
const int M=0x3f3f3f3f;
int visx[N],visy[N];//标记是否已参与这一轮匹配
int x[N],y[N];//最大的匹配权值
int match[N];//i是否已匹配,与谁匹配;
int g1[N][5],g2[N][5],g[N][N];
int n,minv;//宿舍数 最小需调整值
bool dsf(int i)//寻找匹配对象
{
    visx[i]=1;//标记这一轮匹配过
    for(int j=1;j<=n;j++)
    {
        if(visy[j]) continue;

        int tem=x[i]+y[j]-g[i][j];
        if(tem==0)//权值刚好对应上
        {
            visy[j]=1;//尝试匹配 标记
            if(match[j]==-1||dsf(match[j]))//j还未被匹配 或尝试让匹配j的x换一个
            {match[j]=i ;return 1;}//成功匹配

        }
        else if(tem>0) minv=min(tem,minv);//记录需调整数值的最小值
    }return 0;
}
void km()
{
    int i,j;
    for(i=1;i<=n;i++)//x[] y[] match[] 数组初始化
    {
        y[i]=x[i]=0;match[i]=-1;
        for(j=1;j<=n;j++) x[i]=max(x[i],g[i][j]);//找最大值
    }
    for(i=1;i<=n;i++)
    {
        while(1)
        {
            minv=M;
            memset(visx,0,sizeof visx);
            memset(visy,0,sizeof visy);//每一轮初始化一遍 表示开始重新匹配
            if(dsf(i)) break;//匹配成功
            for(j=1;j<=n;j++)//否则 调整参与匹配的各自权值
            {
                if(visx[j]) x[j]-=minv;
                if(visy[j]) y[j]+=minv;
            }
        }
    }
    int ans=0;
    for(i=1;i<=n;i++)
        ans+=g[match[i]][i];
    printf("%d\n",4*n-ans);
}
int main()
{
  int i,j;
  while(cin>>n)
  {
    for(i=1; i<=n; i++)
      for(j=1; j<=4; j++) cin>>g1[i][j];
    for(i=1; i<=n; i++)
      for(j=1; j<=4; j++) cin>>g2[i][j];
    for(i=1; i<=n; i++)
      for(j=1; j<=n; j++)
      {
        int c=0;
        for(int p=1; p<=4; p++)
          for(int k=1; k<=4; k++)
            if(g1[i][p]==g2[j][k]) c++;
        g[i][j]=c;
      }
    km();
  }
}

猜你喜欢

转载自blog.csdn.net/qq_41668093/article/details/81676965