https://www.nowcoder.com/acm/contest/143/E
题意:
给你n个寝室。每个寝室有4个人。
给你第一年的n个寝室的人员分配。再给你第二年的n个寝室的人员分配。
问你最少要让几个人换寝室。不是次数,是人数。
POINT:
把新旧寝室分成二分图。旧寝室到新寝室要搬走的人数很好处理。
这样就是n*n条边的二分图,有权值。 这样就是二分图最小权值匹配。
用最小费用最大流做。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <vector>
#include <bitset>
#include <queue>
using namespace std;
#define LL long long
const int N = 500+3;
const int inf = 0x3f3f3f3f;
struct edge
{
int from,to,cap,flow,cost;
edge(int u,int v,int c,int f,int dd):
from(u),to(v),cap(c),flow(f),cost(dd){}
};
vector<int>G[N];
vector<edge>len;
int s,t;
void add(int u,int v,int cap,int cost)
{
len.push_back(edge(u,v,cap,0,cost));
len.push_back(edge(v,u,0,0,-cost));
G[u].push_back(len.size()-2);
G[v].push_back(len.size()-1);
}
bool spfa(int &ans)
{
int dis[N],pre[N],inq[N];
for(int i=0;i<=t;i++) dis[i]=inf,inq[i]=0,pre[i]=-1;
dis[0]=0;pre[0]=0;inq[0]=1;
int a=inf;
queue<int> q;
q.push(0);
while(!q.empty()){
int u = q.front();q.pop();inq[u]=0;
for(int i=0;i<G[u].size();i++){
edge e=len[G[u][i]];
if(e.cap>e.flow&&dis[e.to]>dis[u]+e.cost){
dis[e.to]=dis[u]+e.cost;
a=min(a,e.cap-e.flow);
pre[e.to]=G[u][i];
if(!inq[e.to]){
q.push(e.to);
inq[e.to]=1;
}
}
}
}
if(dis[t]==inf) return 0;
ans+=dis[t];
int u = t;
while(u!=s){
len[pre[u]].flow+=a;
len[pre[u]^1].flow-=a;
u=len[pre[u]].from;
}
return 1;
}
int mincost()
{
int cost=0;
while(spfa(cost)){
}
return cost;
}
int a[N][5];
int b[N][5];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=4;j++)
scanf("%d",&a[i][j]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=4;j++)
scanf("%d",&b[i][j]);
}
for(int i=1;i<=n;i++){
add(0,i,1,0);
add(i+n,2*n+1,1,0);
for(int j=1;j<=n;j++)//void add(int u,int v,int cap,int cost)
{
int num=0;
for(int k=1;k<=4;k++){
int flag=1;
for(int kk=1;kk<=4;kk++){
if(a[i][k]==b[j][kk]){
flag=0;
break;
}
}
if(flag)
num++;
}
add(i,j+n,1,num);
}
}
s=0,t=2*n+1;
printf("%d\n",mincost());
return 0;
}

本文介绍了一个基于最小费用最大流算法解决寝室人员调整问题的方法。通过构建二分图并使用SPFA算法寻找最小成本匹配,实现了最少人数的寝室调整。

被折叠的 条评论
为什么被折叠?



