Gym - 247731E :room(最小费用流裸题)
题意:有N个宿舍(N<200),给出第一年每个宿舍有哪4个同学。现在给出N个4元组y[][4],表示这4个人想住一起,问最少多少人需要换宿舍。
思路:费用流,每个4元组y[]到每个宿舍连边,流量是1,费用是4-same。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) const int inf=1<<30; const int maxn=1000010; using namespace std; int To[maxn*6],Laxt[maxn],Next[maxn*6],cap[maxn*6],cost[maxn*6]; int S,T,cnt=1,dis[maxn],ans; bool inq[maxn],vis[maxn]; deque<int>q; void add(int u,int v,int c,int cc) { Next[++cnt]=Laxt[u];Laxt[u]=cnt; To[cnt]=v;cap[cnt]=c;cost[cnt]=cc; } bool spfa() { for(int i=0;i<=T;i++) inq[i]=0; for(int i=0;i<=T;i++) dis[i]=inf; inq[T]=1; dis[T]=0; q.push_back(T); while(!q.empty()) { int u=q.front(); q.pop_front(); inq[u]=0; for(int i=Laxt[u];i;i=Next[i]) { int v=To[i]; if(cap[i^1]&&dis[v]>dis[u]-cost[i]) { dis[v]=dis[u]-cost[i]; if(!inq[u]){ inq[v]=1; if(q.empty()||dis[v]>dis[q.front()]) q.push_back(v); else q.push_front(v); } } } } return dis[S]<inf; } int dfs(int u,int flow) { vis[u]=1; if(u==T||flow==0) return flow; int tmp,delta=0; for(int i=Laxt[u];i;i=Next[i]) { int v=To[i]; if((!vis[v])&&cap[i]&&dis[v]==dis[u]-cost[i]) { tmp=dfs(v,min(cap[i],flow-delta)); delta+=tmp; cap[i]-=tmp; cap[i^1]+=tmp; } } return delta; } int x[maxn][4],y[maxn][4]; int main() { int N; scanf("%d",&N); rep(i,1,N) rep(j,0,3) scanf("%d",&x[i][j]); rep(i,1,N) rep(j,0,3) scanf("%d",&y[i][j]); rep(i,1,N) sort(x[i],x[i]+4); rep(i,1,N) sort(y[i],y[i]+4); S=0,T=N+N+1; cnt=1; rep(i,1,N) add(S,i,1,0),add(i,S,0,0); rep(i,1,N) add(N+i,T,1,0),add(T,N+i,0,0); rep(i,1,N) rep(j,1,N) { int L1=0,L2=0,same=0; while(L1<=3&&L2<=3) { if(x[i][L1]==y[j][L2]) same++,L1++,L2++; else if(x[i][L1]<y[j][L2]) L1++; else L2++; } add(i,N+j,1,4-same); add(N+j,i,0,same-4); } int ans=0; while(spfa()){ vis[T]=1; while(vis[T]){ for(int i=0;i<=T;i++) vis[i]=0; ans+=dis[S]*dfs(S,inf); } } printf("%d\n",ans); return 0; }
It is your time to fight!