2016 北京區域賽 現場賽 C—Asa's Chess Problem【有源匯上下界的最小費用最大流】
阿新 • • 發佈:2018-12-13
題意:
給你一個n*n(n<=50)的棋盤,棋盤上每個點0表示白棋,1表示黑棋。
接下來n行,第i行給出棋盤的 第i行 的黑棋數目的上下界[x,y]。
接下來再n行,第i行給出棋盤的 第i列 的黑棋數目的上下界[x,y]。
接下來n*n/2行,每行四個數,x1,y1,x2,y2,表示位置(x1,y1)的棋子可以和位置(x2,y2)的棋子相互交換位置。
保證每個棋子只會輸入一次(可以且只可以交換一次),每兩個可交換的棋子都在同一行或者同一列。
求最少交換次數,使每行每列的黑棋數目都在上下界的範圍內。
如果無解,輸出-1。
分析:
1、新建源點s,匯點t,超級源點sups,超級匯點supt
2、源點s向每行、每列連邊,容量為那一行、那一列的黑棋數目,費用為0
4、對於同一行可交換的棋子,顏色相同忽略,顏色不同黑棋的那一行向白棋的那一行建邊,容量為1,費用為1。
5、對於同一列同上建邊。
程式碼:
#include<bits/stdc++.h> using namespace std; const int maxn=50+10; int n; int chs[maxn][maxn],rl[maxn],cl[maxn],rh[maxn],ch[maxn]; int r[maxn],c[maxn]; int s,t; int sups,supt,digflow; const int maxv=100+10;//最大頂點數 const int inf=2e9;//應大於費用總和 typedef pair<int,int> P; struct Edge{int to,cap,rev,cost;}e; vector<Edge>g[maxv];//圖的鄰接表示 int h[maxv],dist[maxv];//頂點的勢、最短距離,若cost為整數,則為int int prevv[maxv],preve[maxv],V;//最短路中的前驅節點、對應的邊、頂點數 void addedge(int from,int to,int cap,int cost) // 加邊 { e.to=to;e.cap=cap;e.rev=g[to].size();e.cost=cost; g[from].push_back(e); e.to=from;e.cap=0;e.rev=g[from].size()-1;e.cost=-cost; g[to].push_back(e); } void addedge(int from,int to,int low,int up,int cost) { digflow+=low; addedge(sups,to,low,cost); addedge(from,supt,low,cost); addedge(from,to,up-low,cost); } int mincostflow(int s,int t,int f)//求解s~t,流量為f的最小費用 { int res=0; memset(h,0,sizeof(4*t+4)); while(f>0) { priority_queue<P, vector<P>, greater<P> > que; fill(dist,dist+V,inf); dist[s]=0; que.push(P(0,s)); while(!que.empty()) { P p=que.top();que.pop(); int v=p.second; if(dist[v]<p.first) continue; for(int i=0;i<g[v].size();i++) { Edge &E = g[v][i]; if(E.cap>0&&dist[E.to]>dist[v]+E.cost+h[v]-h[E.to]) { dist[E.to]=dist[v]+E.cost+h[v]-h[E.to]; prevv[E.to]=v; preve[E.to]=i; que.push(P(dist[E.to],E.to)); } } } if(dist[t]==inf) return -1; for(int v=0;v<V;v++) h[v]+=dist[v]; //沿s到t的最短路儘量增廣 int d=f; for(int v=t;v!=s;v=prevv[v]) d=min(d,g[prevv[v]][preve[v]].cap); f-=d; res+=h[t]*d; for(int v=t;v!=s;v=prevv[v]) { Edge &E = g[prevv[v]][preve[v]]; E.cap-=d; g[v][E.rev].cap+=d; } } return res; } int main() { while(scanf("%d",&n)!=EOF) { digflow=0; s=2*n+1;sups=0; t=2*n+2;supt=t+1; memset(c,0,sizeof(c)); memset(h,0,sizeof(h)); for(int i=0;i<=supt;i++) g[i].clear(); int mx=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&chs[i][j]); c[j]+=chs[i][j]; h[i]+=chs[i][j]; mx+=chs[i][j]; } for(int i=1;i<=n;i++) { addedge(s,i,h[i],h[i],0); addedge(s,i+n,c[i],c[i],0); } for(int i=1;i<=n;i++) { scanf("%d%d",&rl[i],&rh[i]); addedge(i,t,rl[i],rh[i],0); } for(int i=1;i<=n;i++) { scanf("%d%d",&cl[i],&ch[i]); addedge(i+n,t,cl[i],ch[i],0); } for(int i=1,x1,x2,y1,y2;i<=(n*n)/2;i++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(chs[x1][y1]==chs[x2][y2]) continue; if(chs[x1][y1]==0) swap(x1,x2),swap(y1,y2); if(x1==x2) addedge(n+y1,n+y2,1,1); else addedge(x1,x2,1,1); } addedge(t,s,mx,inf,0); V=2*n+4; int ans=mincostflow(sups,supt,digflow); printf("%d\n",ans); } return 0; }