Exchange pieces problem solution

P3159 [CQOI2012] Exchange pieces

Title :
Insert picture description here

Taking this question as an introductory question for cost flow will really be autistic

Please point out any mistakes, thank you~
Correct solution : First , you can treat the white chess as a blank area, from the starting position to the final position can be seen as the movement of several black chess pieces, and each grid has a limit on the number of visits. Restrictions can be regarded as traffic, and each exchange resembles a cost. At this time, you can think of using the cost flow .
Insert picture description here

First consider the method of not splitting the points, creating an edge for every two adjacent chessboards, but in this case, the limit on the number of visits to each grid cannot be reflected, and there is no way to count the black chess pieces passing from all directions.
Insert picture description here

At this time, consider splitting it into two points. It is conceivable that, except that the starting point and the end point are visited once each time they pass, the points on the path are visited twice. This is indeed no problem, that is, the flow of each point is set to the limit of each grid, the start and end costs of the black chess are set to 1, and the other points are set to 2.
Insert picture description here

A better understanding method is to split into three points. When the access limit is converted into traffic, the traffic will be shared equally between the two edges of the three points, and the cost is 0. For the edge traffic connected to the two grids, the cost is set to infinity. It is 1, and finally counts the minimum cost that can be reached under such a flow limit. See the code for specific details:

#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint register int
#define oo 1e5
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
    
    
  int f = 1; res = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    
     if(c == '-') f = -1; c = getchar(); }
  while(c >= '0' && c <= '9') {
    
     res = res * 10 + c - '0'; c = getchar(); }
  res *= f;
}
const int ne[8][2] = {
    
    1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x7ffffff;
const int N = 1e6+10;
const LL Mod = 1e9+7;
const int M = 30;
struct xx {
    
    
  int next, to, flow, cost;
}e[N];
int tot = 1, head[N];
//起点,终点,流量,花费
void Add(int u, int v, int flow, int cost) {
    
    
  e[++tot] = xx {
    
    head[u], v, flow, cost};
  head[u] = tot;

  e[++tot] = xx {
    
    head[v], u, 0, -cost};
  head[v] = tot;
}
int n, m, s, t;
int dis[N], incf[N], vis[N], pre[N];
queue<int> q;
inline bool spfa() {
    
    
  for(int i = 0; i < N; ++i) dis[i] = INF, vis[i] = pre[i] = 0;
  dis[s] = 0; vis[s] = 1; incf[s] = INF;
  while(!q.empty()) q.pop();
  q.push(s);
  int u, v;
  while(!q.empty()) {
    
    
    u = q.front(); q.pop();
    vis[u] = 0;
    for(int i = head[u]; i; i = e[i].next) {
    
    
      v = e[i].to;
      if(e[i].flow && dis[v] > dis[u] + e[i].cost) {
    
    
        dis[v] = dis[u] + e[i].cost;
        incf[v] = min(incf[u], e[i].flow);
        pre[v] = i;
        if(!vis[v]) vis[v] = 1, q.push(v);
      }
    }
  }
  return dis[t] != INF;
}
int maxflow, mincost;
void MCMF() {
    
    
  while(spfa()) {
    
    
    maxflow += incf[t]; mincost += dis[t] * incf[t];
    for(int i = t; i != s; i = e[pre[i]^1].to) {
    
    
      e[pre[i]].flow -= incf[t], e[pre[i]^1].flow += incf[t];
    }
  }
}
int getp(int k, int x, int y) {
    
     return n*m*k + (x-1)*m + y; }
int tu1[M][M], tu2[M][M];
int main() {
    
    
  scanf("%d%d", &n, &m);
  s = 0; t = n * m * 3 + 1;
  char x;
  int cnt1 = 0, cnt2 = 0;
  
  for(int i = 1; i <= n; ++i) {
    
    
    for(int j = 1; j <= m; ++j) {
    
    
      cin >> x; tu1[i][j] = x - '0';
      //建立源点和黑色棋子起点中间点的边
      if(tu1[i][j]) ++cnt1, Add(s, getp(1, i, j), 1, 0);
    }
  }
  for(int i = 1; i <= n; ++i) {
    
    
    for(int j = 1; j <= m; ++j) {
    
    
      cin >> x; tu2[i][j] = x - '0';
      //建立黑色棋子终点中间点和汇点的边
      if(tu2[i][j]) ++cnt2, Add(getp(1, i, j), t, 1, 0);
    }
  }
  
  for(int i = 1, xx; i <= n; ++i) {
    
    
    for(int j = 1; j <= m; ++j) {
    
    
      cin >> x; xx = x - '0';
      //拆点!左边到中间再到右边
      if(tu1[i][j] == tu2[i][j]) {
    
    
        Add(getp(0, i, j), getp(1, i, j), xx/2, 0);
        Add(getp(1, i, j), getp(2, i, j), xx/2, 0);
      } else if(tu1[i][j]) {
    
    
        Add(getp(0, i, j), getp(1, i, j), xx/2, 0);
        Add(getp(1, i, j), getp(2, i, j), (xx+1)/2, 0);
      } else {
    
    
        Add(getp(0, i, j), getp(1, i, j), (xx+1)/2, 0);
        Add(getp(1, i, j), getp(2, i, j), xx/2, 0);
      }
    }
  }
  if(cnt1 != cnt2)  return puts("-1");

  for(int i = 1, ti, tj; i <= n; ++i) {
    
    
    for(int j = 1; j <= m; ++j) {
    
    
      for(int k = 0; k < 8; ++k) {
    
    
        ti = i + ne[k][0]; tj = j + ne[k][1];
        if(ti < 1 || tj < 1 || ti > n || tj > m) continue;
        //相邻格子之间建立边
        Add(getp(2, i, j), getp(0, ti, tj), INF, 1);
      }
    }
  }
  MCMF();
  printf("%d\n", maxflow == cnt2 ? mincost : -1);
  return 0;
}

Guess you like

Origin blog.csdn.net/qq_43408978/article/details/107655570