Title Link: https://www.nowcoder.com/acm/contest/143/E
Main idea: first, give n 4 groups of data to show the personnel allocation of N dormitories in the first year, then n 4 groups of data to show which students want to live together in the second year. Ask at least several students to make everyone satisfied
Topic idea: build a super source point and super sink point. 1~n represents the dormitory situation of 1~n in the first year. n+1~2*n represents the desired dormitory distribution in the second year. Then, for super source point to 1~n dormitory, for n+1~2*n dormitory to super sink point, build a side with a capacity of 1 and a cost of 0, and then for the first year's dormitory situation and the second year's desired dormitory distribution, the cost is different number of people, and then directly run the template
Here is the code:
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;i++) const int MAXN = 405; const int MAXM=4005; const int inf=0x3f3f3f3f; struct edge{ int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXM],tol,a[MAXN][5],b[MAXN][5]; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N; 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].cap=cap; edge[tol].cost=cost; edge[tol].flow=0; edge[tol].next=head[u]; head[u]=tol++; edge[tol].to=u; edge[tol].cap=0; 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; rep(i,0,N-1){ 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].cap>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 minCostMaxFlow(int s,int t,int &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].cap-edge[i].flow){ Min=edge[i].cap-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 main(){ int n; while(~scanf("%d",&n)){ init(2*n+2); rep(i,1,n) rep(j,1,4) scanf("%d",&a[i][j]); rep(i,1,n) rep(j,1,4) scanf("%d",&b[i][j]); rep(i,1,n){ addedge(0,i,1,0); addedge(i+n,2*n+1,1,0); } rep(i,1,n){ rep(j,1,n){ int num=0; rep(k,1,4){ int flag=0; rep(p,1,4){ if(a[i][k]==b[j][p]){ flag=1; break; } } if(!flag)num++; } addedge(i,j+n,1,num); } } int ans; minCostMaxFlow(0,2*n+1,ans); printf("%d\n",ans); } return 0; }