• Tile Cut~网络流入门题


    Description

    When Frodo, Sam, Merry, and Pippin are at the Green Dragon Inn drinking ale, they like to play a little game with parchment and pen to decide who buys the next round. The game works as follows: Given an m × n rectangular tile with each square marked with one of the incantations W, I, and N, find the maximal number of triominoes that can be cut from this tile such that the triomino has W and N on the ends and I in the middle (that is, it spells WIN in some order). Of course the only possible triominoes are the one with three squares in a straight line and the two ell-shaped ones. The Hobbit that is able to find the maximum number wins and chooses who buys the next round. Your job is to find the maximal number. Side note: Sam and Pippin tend to buy the most rounds of ale when they play this game, so they are lobbying to change the game to Rock, Parchment, Sword (RPS)!

    Input

    Each input file will contain multiple test cases. Each test case consists of an m × n rectangular grid (where 1 ≤ m, n ≤ 30) containing only the letters W, I, and N. Test cases will be separated by a blank line. Input will be terminated by end-of-file.

    Output

    For each input test case, print a line containing a single integer indicating the maximum total number of tiles that can be formed.

    Sample Input

    WIIW
    NNNN
    IINN
    WWWI
    
    NINWN
    INIWI
    WWWIW
    NNNNN
    IWINN
    

    Sample Output

    5
    5

    以前一直不会网络流,直到现在遇到了网络流的题目才决定学一学。
    这题就相当与我的网络流入门题吧。
    这题其实是一个非常容易的网络流题目,只是我以前都不会。
    所以觉得难,多看一些网络流的题目,多了解一些套路就可以了。
    这里我用的是我的dinic模板。
    现在自己仔细讲讲这题如何做,
    题意:给你一张图,求出有几个WIN 。
    网络流的难点就在构图上面,比较各种网络流模板差不多,都是当做
    黑箱使用,如何构图就是一个艺术性的事情了。
    其实这题类似于飞行员匹配问题,只是由两点匹配变成了三点匹配。
    其实就是想办法转化为两点匹配,就是类似于二分图。
    W是头,N是尾,所以主要处理的就是I,
    主要说明一下构图原理,建立一个源点连接到所有的W,然后一个终点连接所有的N
    这里最巧妙的就是in和out,
    源点和out 【n*m,2*n*m-1】相连
    终点和in 【0,n*m-1】 相连
    所以这里处理I 就是将 I 作为连接 in 和 out 的桥梁

       if (tu[i][j] == 'I') {
                for (int k = 0 ; k < 4 ; k++) {
                      int nx = i + dx[k];
                      int ny = j + dy[k];
                      if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                      if (tu[nx][ny] == 'W') f.add(nx * m + ny + out, i * n + j + in, 1) ;
                      if (tu[nx][ny] == 'N') f.add(i * m + j + out, nx * m + ny + in, 1) ;
                }
       }

       这个就是核心代码了。

       想必讲到这里 ,已经是非常非常详细了。

       上代码

    #include <vector>
    #include <stdio.h>
    #include <string>
    #include <cstring>
    #include <queue>
    #include <iostream>
    using namespace std;
    const int maxn = 1e4 + 10;
    const int INF = 1e9 + 7;
    struct node {
        int from, to, cap, flow;
    };
    struct Dinic {
        int n, m, s, t;
        vector<node>nodes;
        vector<int>g[maxn];
        int vis[maxn];
        int d[maxn];
        int cur[maxn];
        void clearall(int n) {
            for (int i = 0 ; i < n ; i++) g[i].clear();
            nodes.clear();
        }
        void clearflow() {
            int len = nodes.size();
            for (int i = 0 ; i < len ; i++) nodes[i].flow = 0;
        }
        void add(int from, int to, int cap) {
            nodes.push_back((node) {
                from, to, cap, 0
            });
            nodes.push_back((node) {
                to, from, 0, 0
            });
            m = nodes.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);
            d[s] = 0;
            vis[s] = 1;
            while(!q.empty()) {
                int x = q.front();
                q.pop();
                int len = g[x].size();
                for (int i = 0 ; i < len ; i++) {
                    node &e = nodes[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, len = g[x].size();
            for (int &i = cur[x] ; i < len ; i++) {
                node & e = nodes[g[x][i]];
                if (d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0 ) {
                    e.flow += f;
                    nodes[g[x][i] ^ 1].flow -= f;
                    flow += f;
                    a -= f;
                    if (a == 0) break;
                }
            }
            return flow;
        }
        int maxflow(int a, int b) {
            s = a;
            t = b;
            int flow = 0;
            while(bfs()) {
                memset(cur, 0, sizeof(cur));
                flow += dfs(s, INF);
            }
            return flow;
        }
        vector<int>mincut() {
            vector<int>ans;
            int len = nodes.size();
            for (int i = 0 ; i < len ; i++) {
                node & e = nodes[i];
                if ( vis[e.from] && !vis[e.to] && e.cap > 0 ) ans.push_back(i);
            }
            return ans;
        }
        void reduce() {
            int len = nodes.size();
            for (int i = 0 ; i < len ; i++) nodes[i].cap -= nodes[i].flow;
        }
    } f;
    int ans(vector<string> &tu ) {
        int n = tu.size(), m = tu[0].length();
        int source = 2 * n * m, sink = 2 * n * m + 1;
        int in = 0, out =  n * m;
        int dx[4] = {0, 1, 0, -1};
        int dy[4] = {1, 0, -1, 0};
        f.clearall(2 * n * m + 2);
        f.clearflow();
        for (int i = 0 ; i < n ; i++) {
            for (int j = 0 ; j < m ; j++) {
                f.add(i * m + j + in, i * m + j + out, 1);
                if (tu[i][j] == 'W') f.add(source, i * m + j + in, 1);
                if (tu[i][j] == 'I') {
                    for (int k = 0 ; k < 4 ; k++) {
                        int nx = i + dx[k];
                        int ny = j + dy[k];
                        if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                        if (tu[nx][ny] == 'W') f.add(nx * m + ny + out, i * m + j + in, 1) ;
                        if (tu[nx][ny] == 'N') f.add(i * m + j + out, nx * m + ny + in, 1) ;
                    }
                }
                if (tu[i][j] == 'N') f.add(i * m + j + out, sink, 1);
            }
        }
        return f.maxflow(source, sink);
    }
    int main() {
        while(1) {
            string s;
            vector<string> tu;
            while(getline(cin, s)) {
                if (s.length() == 0) break;
                tu.push_back(s);
            }
            if (tu.size() == 0) break;
            printf("%d
    ", ans(tu));
        }
        return 0;
    }
  • 相关阅读:
    程序员修神之路--容器技术为什么会这么流行
    程序员修神之路--kubernetes是微服务发展的必然产物
    程序员修神之路--有状态的服务其实可以做更多的事情
    程序员修神之路--要想做好微服务架构,并非易事!
    程序员修神之路--为什么有了SOA,我们还用微服务?
    程序员过关斩将--数据库的乐观锁和悲观锁并非真实的锁
    程序员修神之路--设计一套RPC框架并非易事
    计算机的诞生和简史
    记一次Linux修改MySQL配置不生效的问题
    为什么大多数公司都不重视技术?
  • 原文地址:https://www.cnblogs.com/qldabiaoge/p/8921988.html
Copyright © 2020-2023  润新知