zoukankan      html  css  js  c++  java
  • uva1515 Pool construction

    这里就想到了lrj说的理解EK但是使用Dinic

    因为图较大,所以采用Dinic而不是EdmondsKarp

    得益于接口一致性,无须理解Dinic就能使用它。

    看到最小费用,又有隔开的操作(割),就是最小割,就想到了最大流(想了想用不到MCMF这里挺需要注意的,所有网络流的题首先判断是MCMF还是只是MF

    建图有难度,但是很经典。

    首先把边上的全都变成草。

    添加S,T,就可以把联通块连在一起了

    S连草,边权为d,割断就(叛逃到)T

    边上的草,capINF

    T类似。

    然后任意两个相邻格(原始的,填好了边上之后)之间连U->V,V->UCAP均为d。草到洞的边就割掉

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 50*50+10;
    
    const int INF = 1000000000;
    
    struct Edge {
      int from, to, cap, flow;
    };
    
    bool operator < (const Edge& a, const Edge& b) {
      return a.from < b.from || (a.from == b.from && a.to < b.to);
    }
    
    struct Dinic {
      int n, m, s, t;
      vector<Edge> edges;    // 边数的两倍
      vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
      bool vis[maxn];        // BFS使用
      int d[maxn];           // 从起点到i的距离
      int cur[maxn];         // 当前弧指针
    
      void init(int n) {
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
      }
    
      void AddEdge(int from, int to, int cap) {
        edges.push_back((Edge){from, to, cap, 0});
        edges.push_back((Edge){to, from, 0, 0});
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
      }
    
      bool BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        vis[s] = 1;
        d[s] = 0;
        while(!Q.empty()) {
          int x = Q.front(); Q.pop();
          for(int i = 0; i < G[x].size(); i++) {
            Edge& e = edges[G[x][i]];
            if(!vis[e.to] && e.cap > e.flow) {
              vis[e.to] = 1;
              d[e.to] = d[x] + 1;
              Q.push(e.to);
            }
          }
        }
        return vis[t];
      }
    
      int DFS(int x, int a) {
        if(x == t || a == 0) return a;
        int flow = 0, f;
        for(int& i = cur[x]; i < G[x].size(); i++) {
          Edge& e = edges[G[x][i]];
          if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
            e.flow += f;
            edges[G[x][i]^1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0) break;
          }
        }
        return flow;
      }
    
      int Maxflow(int s, int t) {
        this->s = s; this->t = t;
        int flow = 0;
        while(BFS()) {
          memset(cur, 0, sizeof(cur));
          flow += DFS(s, INF);
        }
        return flow;
      }
    };
    
    Dinic g;
    
    int w, h;
    char pool[99][99];
    
    inline int ID(int i, int j) { return i*w+j; }
    
    int main() {
      int T, d, f, b;
      scanf("%d", &T);
      while(T--) {
        scanf("%d%d%d%d%d", &w, &h, &d, &f, &b);
        for(int i = 0; i < h; i++)
            scanf("%s", pool[i]);
        int cost = 0;
    
    
        for(int i = 0; i < h; i++) {
          if(pool[i][0] == '.') { pool[i][0] = '#'; cost += f; }
          if(pool[i][w-1] == '.') { pool[i][w-1] = '#'; cost += f; }
        }
        for(int i = 0; i < w; i++) {
          if(pool[0][i] == '.') { pool[0][i] = '#'; cost += f; }
          if(pool[h-1][i] == '.') { pool[h-1][i] = '#'; cost += f; }
        }
    
    
        g.init(h*w+2);
    
        for(int i = 0; i < h; i++)
          for(int j = 0; j < w; j++){
    
            if(pool[i][j] == '#') { // grass
              int cap = INF;
              if(i != 0 && i != h-1 && j != 0 && j != w-1)
                cap = d;
              g.AddEdge(h*w, ID(i,j), cap); // s->grass, cap=d or inf  //起点设为S
            }
    
            else { // hole
              g.AddEdge(ID(i,j), h*w+1, f); // hole->t, cap=f
            }
    
            if(i > 0)   g.AddEdge(ID(i,j), ID(i-1,j), b);    //上下左右
            if(i < h-1) g.AddEdge(ID(i,j), ID(i+1,j), b);
            if(j > 0)   g.AddEdge(ID(i,j), ID(i,j-1), b);
            if(j < w-1) g.AddEdge(ID(i,j), ID(i,j+1), b);
          }
        printf("%d
    ", cost + g.Maxflow(h*w, h*w+1));
      }
      return 0;
    }
  • 相关阅读:
    CentOS 6.7 如何启用中文输入法
    10w数组去重,排序,找最多出现次数(精华)
    win10虚拟机搭建Hadoop集群(已完结)
    Linux常用命令
    调用接口显示Required request body is missing
    Git 的使用
    Navicat创建事件,定时更新数据库
    mysql生成UUID
    时间戳与字符串相互转换
    牛客中的错题
  • 原文地址:https://www.cnblogs.com/lqerio/p/9860932.html
Copyright © 2011-2022 走看看