1. 程式人生 > >Tile Cut~網絡流入門題

Tile Cut~網絡流入門題

cas 使用 text nds 現在 clas splay tle add

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\n", ans(tu));
    }
    return 0;
}

Tile Cut~網絡流入門題