链接:https://www.nowcoder.com/acm/contest/143/E
来源:牛客网
题目描述
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.
备注:
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 间宿舍第一年的成员分配情况,再给你第二年所有人想住哪个寝室的分配情况,询问你最小让几个人搬寝室可以达成要求?
思路分析:网络流建图,跑个费用流即可
重点是怎么建图,考虑第二年宿舍的分配情况,去分别匹配第一年的所有宿舍,去计算每种情况需要更换几个人,即为费用,流量是 1
代码示例 :
#include <bits/stdc++.h> using namespace std; const int maxn = 1e4; const int maxm = 1e5; const int inf = 0x3f3f3f3f; struct Edge { int to,next,flow,cost; // flow 表示水现有的流量 }edge[maxm]; int head[maxn],tol; int pre[maxn],dis[maxn]; bool vis[maxn]; int N; //节点个数,编号0->N-1 !全局变量 需要init赋值或主函数改变 void init(int n) { N=n; tol = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,int cost) //边起点,终点,流量,费用 { edge[tol].to = v; edge[tol].cost = cost; edge[tol].flow = cap; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s,int t) //单源最短路径算法 可判断负环 { queue<int >q; for(int i=0;i<N;i++) { dis[i] = inf; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i=head[u];i!=-1;i=edge[i].next) { int v= edge[i].to; if(edge[i].flow && dis[v]>dis[u]+edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t]==-1) return false; else return true; } int MCMF(int s,int t,int &cost) //MinCostMaxFlow 返回最大流,cost存最小费用 { int flow = 0; cost = 0; while(spfa(s,t)) { int Min = inf; for(int i= pre[t];i!=-1;i=pre[edge[i^1].to]) { if(Min>edge[i].flow) Min=edge[i].flow; } for(int i= pre[t];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow -= Min; edge[i^1].flow +=Min; cost += edge[i].cost*Min; } flow += Min; } return flow; } int n; struct node{ int a, b, c, d; }arr[205]; int fun(int x, int y){ int res = 4; if (arr[x].a==arr[y].a || arr[x].a==arr[y].b || arr[x].a==arr[y].c || arr[x].a==arr[y].d) res--; if (arr[x].b==arr[y].a || arr[x].b==arr[y].b || arr[x].b==arr[y].c || arr[x].b==arr[y].d) res--; if (arr[x].c==arr[y].a || arr[x].c==arr[y].b || arr[x].c==arr[y].c || arr[x].c==arr[y].d) res--; if (arr[x].d==arr[y].a || arr[x].d==arr[y].b || arr[x].d==arr[y].c || arr[x].d==arr[y].d) res--; return res; } int main() { cin >> n; for(int i = 1; i <= 2*n; i++){ scanf("%d%d%d%d", &arr[i].a, &arr[i].b, &arr[i].c, &arr[i].d); } init(2*n+2); for(int i = 1; i <= n; i++){ addedge(0, i, 1, 0); addedge(n+i, 2*n+1, 1, 0); for(int j = n+1; j <= 2*n; j++){ addedge(i, j, 1, fun(i, j)); } } int ans; MCMF(0, 2*n+1, ans); printf("%d ", ans); return 0; }