https://www.nowcoder.com/acm/contest/143/E
题意:有n个寝室,每个寝室有四个人,给你第一年和第二年住在一个寝室的人,问要让第一年变成第二年的样子最少需要多少学生换。
思路:把一个寝室当成两个点来看,分别为第一年和第二年的,然后暴力跑每个寝室这两年的学生不一样的个数乘2当做费用,然后用最小费用最大流做
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
struct edge
{
int from,to,cap,flow,cost;
edge(int u,int v,int c,int f,int co):
from(u),to(v),cap(c),flow(f),cost(co){};
};
int n,s,t;
vector<int>g[maxn];
vector<edge>e;
void addedge(int u,int v,int c,int cost)
{
e.push_back(edge(u,v,c,0,cost));
e.push_back(edge(v,u,0,0,-cost));
int zz=e.size();
g[u].push_back(zz-2);
g[v].push_back(zz-1);
}
int cost;
void init(int N)
{
cost=0;
for(int i=0;i<=N;i++)
{
g[i].clear();
}
e.clear();
}
int dis[maxn],pre[maxn],vis[maxn];
bool spfa()
{
queue<int>q;
for(int i=0;i<=t;i++)dis[i]=inf,pre[i]=0;
dis[s]=0;
memset(vis,0,sizeof(vis));
vis[s]=1;
q.push(s);
int a=inf;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<g[u].size();i++)
{
edge f=e[g[u][i]];
if(f.cap>f.flow&&dis[f.to]>dis[u]+f.cost)
{
dis[f.to]=dis[u]+f.cost;
pre[f.to]=g[u][i];
a=min(a,f.cap-f.flow);
if(!vis[f.to])
{
vis[f.to]=1;
q.push(f.to);
}
}
}
}
if(dis[t]==inf)return 0;
int u=t;
cost+=dis[t]*a;
while(u!=s)
{
e[pre[u]].flow+=a;
e[pre[u]^1].flow-=a;
u=e[pre[u]].from;
}
return 1;
}
void mincost()
{
while(spfa())
{
continue;
}
}
int x[150][5],y[150][5];
int main()
{
scanf("%d",&n);
init(2*n+2);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=4;j++)
{
scanf("%d",&x[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=4;j++)
{
scanf("%d",&y[i][j]);
}
}
s=0,t=2*n+1;
for(int i=1;i<=n;i++)
addedge(0,i,1,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int num=0;
for(int a=1;a<=4;a++)
{
int f=0;
for(int b=1;b<=4;b++)
{
if(x[i][a]==y[j][b])
{
f=1;
break;
}
}
if(!f)num++;
}
addedge(i,j+n,1,2*num);
}
}
for(int i=1;i<=n;i++)
addedge(i+n,2*n+1,1,0);
mincost();
printf("%d\n",cost/2);
return 0;
}