码迷,mamicode.com
首页 > 其他好文 > 详细

Tile Cut~网络流入门题

时间:2018-04-23 22:37:36      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:ota   rmi   let   ret   RKE   std   red   oss   艺术性   

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~网络流入门题

标签:ota   rmi   let   ret   RKE   std   red   oss   艺术性   

原文地址:https://www.cnblogs.com/qldabiaoge/p/8921988.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!