zoukankan      html  css  js  c++  java
  • LOJ2321. 「清华集训 2017」无限之环【费用流】

    LINK


    很好的一道网络里题

    首先想插头DP的还是出门左转10分代码吧

    然后考虑怎么网络流
    首先要保证没有漏水
    也就是说每个接口一定要有对应的接口
    那么发现每个点只有可能和上下左右四个点产生联通关系
    所以不妨对图进行黑白染色
    然后把源点连向所有的黑色格子,所有的黑色格子向白色格子连边,所有的白色格子向汇点连边
    那么具体怎么处理每个格子的贡献?
    把每个格子分成四个点分别表示上下左右
    然后我们发现需要转动的只有三种

    1. 只有一个接口
    2. 有两个接口形成L形
    3. 有三个接口

    然后考虑一个接口,相反方向连边代价是2,其他两个方向是1
    L形,转九十度和转二百七十度是代价相等的,然后发现其实如果不考虑顺序的影响因素,本质上只有一个位置变成了另外一个位置
    那么旋转180度也就是两个位置同时变化,刚好是变化一次代价为1,是不是很神奇呢
    然后三个接口的情况类似,需要分类讨论,但是并不复杂,和两个的情况类似

    然后建图建完了就可以费用流了

    我怎么这么慢。。。

    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    typedef pair<int, int> pi;
    //convenient for
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 1.6e7 + 10;
    const int M = 2e3 + 10;
    namespace Min_Cost_Max_Flow {
    struct Edge{
      int u, v, cap, flow, cost;
    };
    int S, T;
    int dis[N], pre[N], f[N];
    bool inq[N];
    vector<Edge> E;
    vector<int> G[N];
    void add(int u, int v, int cap, int cost) {
      E.push_back((Edge){u, v, cap, 0, cost});
      E.push_back((Edge){v, u, 0, 0, -cost});
      int m = E.size();
      G[u].push_back(m - 2);
      G[v].push_back(m - 1);
    }
    bool spfa(int &flow, int &cost) {
      static queue<int> q;
      fu(i, 1, T) dis[i] = INF_of_int;
      dis[S] = 0;
      f[S] = INF_of_int;
      q.push(S);
      while(!q.empty()){
        int u = q.front();q.pop();
        inq[u] = 0;
        fv(i, G[u]) {
          Edge e = E[G[u][i]];
          if (e.cap > e.flow && dis[e.v] > dis[u] + e.cost) {
            dis[e.v] = dis[u] + e.cost;
            pre[e.v] = G[u][i];
            f[e.v] = min(f[u], e.cap - e.flow);
            if (!inq[e.v]) inq[e.v] = 1, q.push(e.v);
          }
        }
      }
      if (dis[T] == INF_of_int) return 0;
      flow += f[T];
      cost += f[T] * dis[T];
      int u = T;
      while (u != S) {
        E[pre[u]].flow += f[T];
        E[pre[u] ^ 1].flow -= f[T];
        u = E[pre[u]].u;
      }
      return 1;
    }
    pi mcmf() {
      int flow = 0, cost = 0;
      while(spfa(flow, cost));
      return pi(flow, cost);
    }
    };
    int n, m, cnt = 0;
    struct Point{
      bool l, r, u, d;
      int typ;
      //typ = 1 one interface
      //typ = 2 tow interfaces in different line
      //typ = 3 tow interfaces in the same line (useless)
      //typ = 4 three interfaces
      //typ = 5 four interfaces (useless)
      int l_id, r_id, u_id, d_id;
    }g[M][M];
    int mx[4] = {-1, 0, 1, 0};
    int my[4] = {0, 1, 0, -1};
    void insert_single_point(Point p, int typ) {
      if (typ) { //black
        if (p.l) Min_Cost_Max_Flow::add(Min_Cost_Max_Flow::S, p.l_id, 1, 0);
        if (p.r) Min_Cost_Max_Flow::add(Min_Cost_Max_Flow::S, p.r_id, 1, 0);
        if (p.u) Min_Cost_Max_Flow::add(Min_Cost_Max_Flow::S, p.u_id, 1, 0);
        if (p.d) Min_Cost_Max_Flow::add(Min_Cost_Max_Flow::S, p.d_id, 1, 0);
      } else { //white
        if (p.l) Min_Cost_Max_Flow::add(p.l_id, Min_Cost_Max_Flow::T, 1, 0);
        if (p.r) Min_Cost_Max_Flow::add(p.r_id, Min_Cost_Max_Flow::T, 1, 0);
        if (p.u) Min_Cost_Max_Flow::add(p.u_id, Min_Cost_Max_Flow::T, 1, 0);
        if (p.d) Min_Cost_Max_Flow::add(p.d_id, Min_Cost_Max_Flow::T, 1, 0);
      }
    }
    void add_edge_single_point_case_1(Point p, int typ) {
      if (p.l) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.l_id, p.r_id, 1, 2);
          Min_Cost_Max_Flow::add(p.l_id, p.u_id, 1, 1);
          Min_Cost_Max_Flow::add(p.l_id, p.d_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.r_id, p.l_id, 1, 2);
          Min_Cost_Max_Flow::add(p.u_id, p.l_id, 1, 1);
          Min_Cost_Max_Flow::add(p.d_id, p.l_id, 1, 1);
        }
      }
      if (p.r) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.r_id, p.l_id, 1, 2);
          Min_Cost_Max_Flow::add(p.r_id, p.u_id, 1, 1);
          Min_Cost_Max_Flow::add(p.r_id, p.d_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.l_id, p.r_id, 1, 2);
          Min_Cost_Max_Flow::add(p.u_id, p.r_id, 1, 1);
          Min_Cost_Max_Flow::add(p.d_id, p.r_id, 1, 1);
        }
      }
      if (p.u) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.u_id, p.d_id, 1, 2);
          Min_Cost_Max_Flow::add(p.u_id, p.l_id, 1, 1);
          Min_Cost_Max_Flow::add(p.u_id, p.r_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.d_id, p.u_id, 1, 2);
          Min_Cost_Max_Flow::add(p.l_id, p.u_id, 1, 1);
          Min_Cost_Max_Flow::add(p.r_id, p.u_id, 1, 1);
        }
      }
      if (p.d) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.d_id, p.u_id, 1, 2);
          Min_Cost_Max_Flow::add(p.d_id, p.l_id, 1, 1);
          Min_Cost_Max_Flow::add(p.d_id, p.r_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.u_id, p.d_id, 1, 2);
          Min_Cost_Max_Flow::add(p.l_id, p.d_id, 1, 1);
          Min_Cost_Max_Flow::add(p.r_id, p.d_id, 1, 1);
        }
      }
    }
    void add_edge_single_point_case_2(Point p, int typ) {
      if (p.l) {
         if (typ) {
           Min_Cost_Max_Flow::add(p.l_id, p.r_id, 1, 1);
         } else {
           Min_Cost_Max_Flow::add(p.r_id, p.l_id, 1, 1);
         }
      }
      if (p.r) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.r_id, p.l_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.l_id, p.r_id, 1, 1);
        }
      }
      if (p.u) {
        if (typ) {  
          Min_Cost_Max_Flow::add(p.u_id, p.d_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.d_id, p.u_id, 1, 1);
        }
      }
      if (p.d) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.d_id, p.u_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.u_id, p.d_id, 1, 1);
        }
      }
    }
    void add_edge_single_point_case_3(Point p, int typ) {
      if (!p.l) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.r_id, p.l_id, 1, 2);
          Min_Cost_Max_Flow::add(p.u_id, p.l_id, 1, 1);
          Min_Cost_Max_Flow::add(p.d_id, p.l_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.l_id, p.r_id, 1, 2);
          Min_Cost_Max_Flow::add(p.l_id, p.u_id, 1, 1);
          Min_Cost_Max_Flow::add(p.l_id, p.d_id, 1, 1);
        }
      }
      if (!p.r) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.l_id, p.r_id, 1, 2);
          Min_Cost_Max_Flow::add(p.u_id, p.r_id, 1, 1);
          Min_Cost_Max_Flow::add(p.d_id, p.r_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.r_id, p.l_id, 1, 2);
          Min_Cost_Max_Flow::add(p.r_id, p.u_id, 1, 1);
          Min_Cost_Max_Flow::add(p.r_id, p.d_id, 1, 1);
        }
      }
      if (!p.u) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.d_id, p.u_id, 1, 2);
          Min_Cost_Max_Flow::add(p.l_id, p.u_id, 1, 1);
          Min_Cost_Max_Flow::add(p.r_id, p.u_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.u_id, p.d_id, 1, 2);
          Min_Cost_Max_Flow::add(p.u_id, p.l_id, 1, 1);
          Min_Cost_Max_Flow::add(p.u_id, p.r_id, 1, 1);
        }
      }
      if (!p.d) {
        if (typ) {
          Min_Cost_Max_Flow::add(p.u_id, p.d_id, 1, 2);
          Min_Cost_Max_Flow::add(p.l_id, p.d_id, 1, 1);
          Min_Cost_Max_Flow::add(p.r_id, p.d_id, 1, 1);
        } else {
          Min_Cost_Max_Flow::add(p.d_id, p.u_id, 1, 2);
          Min_Cost_Max_Flow::add(p.d_id, p.l_id, 1, 1);
          Min_Cost_Max_Flow::add(p.d_id, p.r_id, 1, 1);
        }
      }
    }
    void add_edge_between_points(Point a, Point b, int dir) {
      if (dir == 0) Min_Cost_Max_Flow::add(a.u_id, b.d_id, 1, 0);
      if (dir == 1) Min_Cost_Max_Flow::add(a.r_id, b.l_id, 1, 0);
      if (dir == 2) Min_Cost_Max_Flow::add(a.d_id, b.u_id, 1, 0);
      if (dir == 3) Min_Cost_Max_Flow::add(a.l_id, b.r_id, 1, 0);
    }
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      Read(n);Read(m);
      int sum = 0;
      Min_Cost_Max_Flow::S = 0;
      Min_Cost_Max_Flow::T = n * m * 4 + 1;
      fu(i, 1, n) {
        fu(j, 1, m) {
          int w;Read(w);
          g[i][j].u = (w & (1 << 0)); g[i][j].u_id = ++cnt;
          g[i][j].r = (w & (1 << 1)); g[i][j].r_id = ++cnt;
          g[i][j].d = (w & (1 << 2)); g[i][j].d_id = ++cnt;
          g[i][j].l = (w & (1 << 3)); g[i][j].l_id = ++cnt;
          int num = g[i][j].u + g[i][j].r + g[i][j].d + g[i][j].l;
          sum += num;
          if (num == 1) {
            add_edge_single_point_case_1(g[i][j], (i + j) & 1);
          } else if (num == 2) {
            if ((!g[i][j].u || !g[i][j].d) && (!g[i][j].l || !g[i][j].r))
              add_edge_single_point_case_2(g[i][j], (i + j) & 1);
          } else if (num == 3) {
            add_edge_single_point_case_3(g[i][j], (i + j) & 1);
          }
          insert_single_point(g[i][j], (i + j) & 1);
        }
      }
      fu(i, 1, n) {
        fu(j, 1, m) {
          if ((i + j) & 1) {
            fu(k, 0, 3) {
              int ni = i + mx[k], nj = j + my[k];
              if (ni < 1 || ni > n || nj < 1 || nj > m) continue;
              add_edge_between_points(g[i][j], g[ni][nj], k);
            }
          }
        }
      }
      pi res = Min_Cost_Max_Flow::mcmf();
      if (res.first * 2 != sum) Write(-1);
      else Write(res.second);
      return 0;
    }
    
  • 相关阅读:
    python-模块-tkinter
    Linux-命令-基本-反引号``或$()
    Linux-命令-基本-time,ctime,atime
    Linux-命令-基本-find-exec
    Linux-命令-cp,mkdir
    Linux-命令-setup,ifup,ls,cd,touch重定向
    Linux-Buffer和Cache
    给Access数据库文件减肥
    GPT转MBR怎么转?
    Windows XP解决显示桌面图标消失的问题
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9738864.html
Copyright © 2011-2022 走看看