Mr.Panda and TubeMaster Gym - 101194J (二分染色有源匯上下界最大費用流)
阿新 • • 發佈:2018-11-15
Mr.Panda and TubeMaster
題目連結就這樣了,題面難得獲得就算了。
題目大意:
給出一面方格紙,上面佈滿了方格,方格中能且只能如下圖部署水管:
每兩個方格之間連線具有一定的收益,問在滿足所有的水管成環,且一些水管必須經過的前提下可以獲得的最大收益是多少。
思路:
很容易感覺出來,這應該是一個費用流問題。但是顯然得,解決起來並不簡單。
首先,我們為方格進行染色,使得一些方格只能橫向出縱向入,而他們相鄰的方格只能縱向出橫向入,這樣就可以保證任意環內的流向是一致的,再接著對不是必須經過的點連上一條費用為0的邊,這樣就保證這些點必然可以經過,因為他們並不佔用額外的流量,假如流量不等於方格的總數,則必然是那些必須經過的點沒有被經過。最終跑一遍費用流即可
AC程式碼:
#include<cstring> #include<queue> #include<vector> #include<iostream> using namespace std; const int maxn=2005; const int INF=0x3f3f3f3f; struct Edge{ int from,to,cap,flow,cost; Edge(){} Edge(int from,int to,int cap,int flow,int cost):from(from),to(to),cap(cap),flow(flow),cost(cost){} }; struct MCMF { int n,m,s,t; vector<Edge> edges; vector<int> g[maxn]; int inq[maxn]; int d[maxn]; int p[maxn]; int a[maxn]; void init(int n) { this->n =n; for(int i=0; i<n; i++)g[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost) { Edge e1= Edge(from,to,cap,0,cost), e2= Edge(to,from,0,0,-cost); edges.push_back(e1); edges.push_back(e2); m=edges.size(); g[from].push_back(m-2); g[to].push_back(m-1); } bool spfa(int s,int t, int & flow,int & cost) { for(int i=0; i<=n; i++) d[i]=INF; memset(inq,0,sizeof(inq)); d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=0; i<g[u].size(); i++) { Edge & e = edges[g[u][i]]; if(e.cap>e.flow && d[e.to]>d[u]+e.cost) { d[e.to]=d[u]+e.cost; p[e.to]=g[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]) { q.push(e.to); inq[e.to]=1; } } } } if(d[t]==INF) return false; flow+=a[t]; cost+=a[t]*d[t]; for(int u=t; u!=s; u=edges[p[u]].from) { edges[p[u]].flow +=a[t]; edges[p[u]^1].flow-=a[t]; } return true; } pair<int,int> Mincost(int s,int t) { int flow=0,cost =0; while(spfa(s,t,flow,cost)); return pair<int,int>(cost,flow); } }; int idl[35][35],idr[35][35]; int valr[35][35],valc[35][35]; int vis[35][35]; int main() { int t; int kace=1; scanf("%d",&t); while(t--){ memset(vis,0,sizeof(vis)); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<m;j++) { scanf("%d",&valc[i][j]); } } for(int i=1;i<n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&valr[i][j]); } } MCMF pro; int cnt=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { idl[i][j]=++cnt;idr[i][j]=++cnt; } } pro.init(cnt+10); int ss=0,tt=cnt+1; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if((i+j)&1) { if(j+1<=m) pro.AddEdge(idl[i][j],idr[i][j+1],1,-valc[i][j]); if(j-1>=1) pro.AddEdge(idl[i][j],idr[i][j-1],1,-valc[i][j-1]); } else { if(i+1<=n) pro.AddEdge(idl[i][j],idr[i+1][j],1,-valr[i][j]); if(i-1>=1) pro.AddEdge(idl[i][j],idr[i-1][j],1,-valr[i-1][j]); } } } int k; scanf("%d",&k); while(k--) { int x,y; scanf("%d%d",&x,&y); vis[x][y]=1; } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { pro.AddEdge(ss,idl[i][j],1,0); pro.AddEdge(idr[i][j],tt,1,0); if(!vis[i][j]) pro.AddEdge(idl[i][j],idr[i][j],1,0); } } printf("Case #%d: ",kace++); pair<int,int> ans=pro.Mincost(ss,tt); if(ans.second!=n*m) printf("Impossible\n"); else printf("%d\n",-ans.first); } }