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

题目大意:

有n个宿舍,每个宿舍住了四个人。年末宿舍需要重新分配。你收到了n份宿舍的人员请求,求问怎样安排宿舍使得交换的次数最少。

解题思路:

刚开始想了一下,然后队友发现对于新旧的宿舍可以建边,它们的权值就是两个宿舍相同的人数。然后直接跑km算法即可。

最后用总人数减去跑出来的权值就是答案。

Ac代码:

#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=500+10;
const int INF=1e9+7;
const int mod=998244353;
typedef long long ll;
int n;
struct node
{
    int s[5];
}a[maxn],b[maxn];
int nx,ny;
int g[maxn][maxn];
int linker[maxn],lx[maxn],ly[maxn];
int slack[maxn];
bool visx[maxn],visy[maxn];
bool dfs(int x)
{
    visx[x]=1;
    for(int y=0;y<ny;y++)
    {
        if(visy[y]) continue;
        int tmp=lx[x]+ly[y]-g[x][y];
        if(tmp==0)
        {
            visy[y]=1;
            if(linker[y]==-1||dfs(linker[y]))
            {
                linker[y]=x;
                return 1;
            }
        }
        else if(slack[y]>tmp)
            slack[y]=tmp;
    }
    return 0;
}
int km()    //kuangbin模板 
{
    memset(linker,-1,sizeof linker);
    memset(ly,0,sizeof ly);
    for(int i=0;i<nx;i++)
    {
        lx[i]=-INF;
        for(int j=0;j<ny;j++)
        {
            if(g[i][j]>lx[i])
                lx[i]=g[i][j];
        }
    }
    for(int x=0;x<nx;x++)
    {
        for(int i=0;i<ny;i++) slack[i]=INF;
        while(1)
        {
            memset(visx,0,sizeof visx);
            memset(visy,0,sizeof visy);
            if(dfs(x)) break;
            int d=INF;
            for(int i=0;i<ny;i++)
                if(!visy[i]&&d>slack[i])
                    d=slack[i];
            for(int i=0;i<nx;i++)
                if(visx[i])
                    lx[i]-=d;
            for(int i=0;i<ny;i++)
            {
                if(visy[i]) ly[i]+=d;
                else slack[i]-=d;
            }
        }
    }
    int res=0;
    for(int i=0;i<ny;i++)
        if(linker[i]!=-1)
            res+=g[linker[i]][i];
    return res;
}
bool vis[500];
int cal(int x,int y)    //判断相同人数
{
    int res=0;
    memset(vis,0,sizeof vis);
    for(int i=1;i<=4;i++) vis[a[x].s[i]]=1;
    for(int i=1;i<=4;i++)
        if(vis[b[y].s[i]]) res++;
    return res;
}
void build()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            g[i][j]=cal(i,j);
            g[j][i]=cal(j,i);
        }
    }
    nx=n,ny=n;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)    //输入人员清单
        scanf("%d%d%d%d",&a[i].s[1],&a[i].s[2],&a[i].s[3],&a[i].s[4]);
    for(int i=0;i<n;i++)
        scanf("%d%d%d%d",&b[i].s[1],&b[i].s[2],&b[i].s[3],&b[i].s[4]);
    build();
    printf("%d\n",4*n-km()); //得出答案
    //system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/f2935552941/article/details/81461022