题目描述
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,2,3,4)->(1,2,3,5)权值为3。然后用KM算法找最大匹配边权。
如果是最大流,以换宿舍的人作为费用的话,只需要求每个宿舍i和现在的宿舍j中有 多少个不同的人作为费用建边,流量为1,答案就是最大流时的总费用。
如果是费用流,以不换宿舍的人建边的话,要使在原来宿舍的人越多的宿舍先不换宿舍,那么每个宿舍i和现在的宿舍j中有多少个相同的人,建边两种宿舍的费用就是 4-相同的人数 ,流量为1。答案就是4*n+最大流的总费用。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define clear(A, X) memset(A, X, sizeof A)
#define min(A, B) ((A) < (B) ? (A) : (B))
using namespace std;
const int maxE = 2000000;
const int maxN = 256;
const int oo = 0x3f3f3f3f;
struct Edge{
int v, c, w, n;
Edge(){}
Edge(int V, int C, int W, int N) : v(V), c(C), w(W), n(N){}
};
struct Node{
int l, r, w;
};
struct poin
{
int x,y;
}x1[300],x2[300];
Edge edge[maxE];
Node sche[maxN];
int adj[maxN], cntE;
int Q[maxE], head, tail;
int d[maxN], inq[maxN], cur[maxN], f[maxN];
int cost, flow, s, t;
int N, M, K;
void addedge(int u, int v, int c, int w){
edge[cntE] = Edge(v, c, w, adj[u]); adj[u] = cntE++;
edge[cntE] = Edge(u, 0, -w, adj[v]); adj[v] = cntE++;
}
int spfa(){
f[s] = oo;
clear(d, oo);
clear(inq, 0);
cur[s] = -1;
d[s] = 0;
head = tail = 0;
Q[tail++] = s;
inq[s] = 1;
while(head != tail){
int u = Q[head++];
inq[u] = 0;
for(int i = adj[u]; ~i; i = edge[i].n){
int v = edge[i].v, c = edge[i].c, w = edge[i].w;
if(c && d[v] > d[u] + w){
d[v] = d[u] + w;
f[v] = min(f[u], c);
cur[v] = i;
if(!inq[v]){
Q[tail++] = v;
inq[v] = 1;
}
}
}
}
if(d[t] == oo) return 0;
flow += f[t];
cost += d[t] * f[t];
for(int i = cur[t]; ~i; i = cur[edge[i ^ 1].v]){
edge[i].c -= f[t];
edge[i ^ 1].c += f[t];
}
return 1;
}
int MCMF(){
flow = cost = 0;
while(spfa());
return cost;
}
void init(){
clear(adj, -1);
cntE = 0;
}
int a[110][4];
int b[110][4];
int get(int x, int y) {
int res = 0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if (a[x][i] == b[y][j]) res++;
return res;
}
int S,T;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)for(int j=0;j<4;j++)scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)for(int j=0;j<4;j++)scanf("%d",&b[i][j]);
s=0;t=2*n+1;
init();
for(int i=1;i<=n;i++)
{
addedge(s, i, 1, 0);
addedge(n + i, t, 1, 0);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
addedge(i, n + j, 1, -get(i, j));
cout << 4 * n + MCMF();
return 0;
}
/*
2
1 2 3 4
5 6 7 8
4 6 7 8
1 2 3 5
*/