题意:给你一个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; }