[BZOJ 2668] 交换棋子
Link:
Solution:
重点在于对于每条转移路径:首尾算一次,中间节点算两次
可以一点拆三点,将原流量拆成入流量和出流量
但其实也可以就拆两点,分前后是否是一首尾点一普通点来确定是否有一条路径只占用1流量
Code:
#include <bits/stdc++.h> using namespace std; #define X first #define Y second typedef long long ll; typedef pair<int,int> P; const int MAXN=1e5+10,INF=1<<30; int n,m,cnt1,cnt2;char dat[2][30][30],lmt[30][30]; namespace mcmf { struct edge {int to,cap,cost,rev;}; vector<edge> a[MAXN]; int S,T,h[MAXN],dist[MAXN],preV[MAXN],preE[MAXN],maxf,minc; void add_edge(int from,int to,int cap,int cost) { a[from].push_back(edge{to,cap,cost,a[to].size()}); a[to].push_back(edge{from,0,-cost,a[from].size()-1}); } void min_cost_flow(int f) { while(f>0) { priority_queue<P,vector<P>,greater<P> > que; fill(dist,dist+T+1,INF); dist[S]=0;que.push(P(0,S)); while(!que.empty()) { P t=que.top();que.pop(); int v=t.Y;if(dist[v]<t.X) continue; for(int i=0;i<a[v].size();i++) { edge &e=a[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], preV[e.to]=v,preE[e.to]=i,que.push(P(dist[e.to],e.to)); } } if(dist[T]==INF) break; for(int i=1;i<=T;i++) h[i]+=dist[i]; int d=f; for(int i=T;i!=S;i=preV[i]) d=min(d,a[preV[i]][preE[i]].cap); f-=d;minc+=d*h[T];maxf+=d; for(int i=T;i!=S;i=preV[i]) { edge &e=a[preV[i]][preE[i]]; e.cap-=d,a[i][e.rev].cap+=d; } } } } using namespace mcmf; int dx[]={1,1,1,-1,-1,-1,0,0}; int dy[]={1,-1,0,1,-1,0,1,-1}; int idx(int x,int y,int z){return (x-1)*m+y+n*m*z;} int main() { scanf("%d%d",&n,&m); S=0;T=2*n*m+1; for(int i=1;i<=n;i++) scanf("%s",dat[0][i]+1); for(int i=1;i<=n;i++) scanf("%s",dat[1][i]+1); for(int i=1;i<=n;i++) scanf("%s",lmt[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(dat[0][i][j]=='1') cnt1++,add_edge(S,idx(i,j,0),1,0); if(dat[1][i][j]=='1') cnt2++,add_edge(idx(i,j,1),T,1,0); if(dat[0][i][j]==dat[1][i][j]) add_edge(idx(i,j,0),idx(i,j,1),(lmt[i][j]-'0')/2+dat[0][i][j]-'0',0); else add_edge(idx(i,j,0),idx(i,j,1),(lmt[i][j]-'0'+1)/2,0); for(int k=0;k<8;k++) { int fx=i+dx[k],fy=j+dy[k]; if(fx<1||fx>n||fy<1||fy>m) continue; add_edge(idx(i,j,1),idx(fx,fy,0),INF,1); } } min_cost_flow(INF); if(cnt1!=cnt2||maxf!=cnt1) puts("-1"); else printf("%d",minc); return 0; }