题目链接:https://www.nowcoder.com/acm/contest/143/E
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Nowcoder University has 4n students and n dormitories ( Four students per dormitory). Students numbered from 1 to 4n.
And in the first year, the i-th dormitory 's students are (x1[i],x2[i],x3[i],x4[i]), now in the second year, Students need to decide who to live with.
In the second year, you get n tables such as (y1,y2,y3,y4) denote these four students want to live together.
Now you need to decide which dormitory everyone lives in to minimize the number of students who change dormitory.
输入描述:
The first line has one integer n.
Then there are n lines, each line has four integers (x1,x2,x3,x4) denote these four students live together in the first year
Then there are n lines, each line has four integers (y1,y2,y3,y4) denote these four students want to live together in the second year
输出描述:
Output the least number of students need to change dormitory.
输入
2 1 2 3 4 5 6 7 8 4 6 7 8 1 2 3 5
输出
2
说明
Just swap 4 and 5
备注
1<=n<=100
1<=x1,x2,x3,x4,y1,y2,y3,y4<=4n
It's guaranteed that no student will live in more than one dormitories.
题意:
现有n个宿舍,4n个学生,即一个宿舍四个学生,学生从1~4n编号,
第一年,每个宿舍x1[i],x2[i],x3[i],x4[i]代表四个学生,
现在第二年,有n张表,每张表上y1,y2,y3,y4代表该宿舍四个学生分别想和谁一起住,
现在需要决策每个学生住哪个宿舍,使得换宿舍的学生数最少,输出这个数。
题解:
转化为最小费用最大流解决的二分图问题,对每个去年的宿舍,向每个今年的组合连一条边,权值为1,费用为需要搬的人数(4-相同的人数),源点到去年各点,今年各点到汇点,都连一条权值为1费用为0的最大流,跑一次费用流即可。(参考https://www.nowcoder.com/discuss/90015?type=101&order=0&pos=1&page=0)
说实话,第一次看到这题比较懵逼的,因为以为宿舍必须住四个人,但是看了题解之后,发现好像没有规定宿舍住的人数。
AC代码:
#include<bits/stdc++.h> using namespace std; const int maxn=110; const int INF=0X3f3f3f3f; struct Edge{ int u,v,c,f,a; }; struct MCMF { int s,t; vector<Edge> E; vector<int> G[2*maxn]; int vis[2*maxn]; int d[2*maxn]; int pre[2*maxn]; int aug[2*maxn]; void init(int l,int r) { for(int i=l;i<=r;i++) G[i].clear(); E.clear(); } void addedge(int from,int to,int cap,int cost) { E.push_back((Edge){from,to,cap,0,cost}); E.push_back((Edge){to,from,0,0,-cost}); int m=E.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool SPFA(int s,int t,int &flow,int &cost) { memset(d,INF,sizeof(d)); memset(vis,0,sizeof(vis)); d[s]=0, vis[s]=1, pre[s]=0, aug[s]=INF; queue<int> q; q.push(s); while(!q.empty()) { int now=q.front(); q.pop(); vis[now]=0; for(int i=0;i<G[now].size();i++) { Edge& e=E[G[now][i]]; int nex=e.v; if(e.c>e.f && d[nex]>d[now]+e.a) { d[nex]=d[now]+e.a; pre[nex]=G[now][i]; aug[nex]=min(aug[now],e.c-e.f); if(!vis[nex]) { q.push(nex); vis[nex]=1; } } } } if(d[t]==INF) return 0; flow+=aug[t]; cost+=d[t]*aug[t]; for(int i=t;i!=s;i=E[pre[i]].u) { E[pre[i]].f+=aug[t]; E[pre[i]^1].f-=aug[t]; } return 1; } int mincost() { int flow=0,cost=0; while(SPFA(s,t,flow,cost)); return cost; } }mcmf; int n; struct Dorm{ int x[4]; }fst[maxn],snd[maxn]; int cost(Dorm fst,Dorm snd) { int res=4; for(int i=0;i<4;i++) { bool stay=0; for(int j=0;j<4;j++) stay|=(fst.x[i]==snd.x[j]); res-=stay; } return res; } int main() { scanf("%d",&n); mcmf.init(0,2*n+1); mcmf.s=0, mcmf.t=2*n+1; for(int i=1;i<=n;i++) for(int k=0;k<4;k++) scanf("%d",&fst[i].x[k]); for(int i=1;i<=n;i++) for(int k=0;k<4;k++) scanf("%d",&snd[i].x[k]); for(int i=1;i<=n;i++) { mcmf.addedge(mcmf.s,i,1,0); mcmf.addedge(n+i,mcmf.t,1,0); for(int j=1;j<=n;j++) mcmf.addedge(i,n+j,1,cost(fst[i],snd[j])); } printf("%d ",mcmf.mincost()); }