题意:给你一个n,代表一共有n个宿舍,每个宿舍4个人。然后给你初始这4n个学生的信息,也就是开始时谁与谁在一个宿舍。然后又给你新的信息,表示搬宿舍后,希望谁跟谁在一个宿舍,问如何安排让哪些学生从旧宿舍搬走,使得搬后在一个宿舍的学生符合新的信息,要求输出最少搬动的人数。
其实我也是看了别人的代码,才推理出来这题的解法,不过看居然没有题解,就让我来介绍一下这题的解法吧。
思路:考虑如何建图,可以将一个宿舍视作一个点,旧的宿舍信息有n个点, 新的宿舍信息也有n个点,然后目的是让搬宿舍的人最少,考虑最小费用最大流。那么对于任意的两个宿舍,一新一旧之间,我们连一条边,费用就是指让旧宿舍搬成新宿舍,需要搬走多少人,那么明显这条边的费用就是4减去两个宿舍中相同的人数(这里可以直接两个for循环遍历新旧宿舍,先将初始费用设置为4,对于旧宿舍每个人,遍历对应新宿舍,遇到同样的人,费用减一),然后设立一个源点s,s与每个旧宿舍之间连一条费用为0的边,新宿舍再跟每个汇点t连一条费用为0的边,所有的边流量都是1,然后跑最小费用最大流,总费用就是最少需要的搬家人数了。
下面是代码展示
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int mod=998244353;
const int maxn=1e3+10;
const int maxm=1e5+10;
int n,s,t,dis[maxn],pre[maxn],lst[maxn],flow[maxn],vis[maxn];
int maxflow,mincost;//需要的最大流、最小费用
int old[maxn][6],now[maxn][6];
struct Node{
    int to,nxt;
    int flow,dis;//flow流量,dis花费
}e[maxm<<1];
int cnt=1,head[maxn];
void add(int u,int v,int w,int x){//建反向边,花费也是相反数
    e[++cnt].to=v;
    e[cnt].flow=w;
    e[cnt].nxt=head[u];
    e[cnt].dis=x;
    head[u]=cnt;
    e[++cnt].to=u;
    e[cnt].flow=0;
    e[cnt].nxt=head[v];
    e[cnt].dis=-x;
    head[v]=cnt;
}
int spfa(){
    for(int i=0;i<=n*2+1;i++) dis[i]=inf,flow[i]=inf,vis[i]=0;
    queue<int>q;
    q.push(s);vis[s]=1;dis[s]=0;pre[t]=-1;
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(e[i].flow>0&&dis[v]>dis[u]+e[i].dis){
                dis[v]=dis[u]+e[i].dis;
                pre[v]=u;
                lst[v]=i;
                flow[v]=min(flow[u],e[i].flow);
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[t]!=-1;
}
void MCMF(){//min cost max flow
    while(spfa()){
        int now=t;
        maxflow+=flow[t];
        mincost+=flow[t]*dis[t];
        while(now!=s){
            e[lst[now]].flow-=flow[t];
            e[lst[now]^1].flow+=flow[t];
            now=pre[now];
        }
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    s=0;t=2*n+1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=4;j++)
            cin>>old[i][j];
        add(s,i,1,0);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=4;j++)
            cin>>now[i][j];
        add(n+i,t,1,0);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            int tem=4;
            for(int k=1;k<=4;k++)
                for(int l=1;l<=4;l++){
                    tem-=(old[i][k]==now[j][l]);
                }
            add(i,n+j,1,tem);
        }
    MCMF();
    cout<<mincost<<endl;
    //system("pause");
    return 0;
}