Codeforces Gym 100203I I WIN 最大流

原题链接:http://codeforces.com/gym/100203/attachments/download/1702/statements.pdf

题解

首先寻找每个I,然后枚举形状,如果匹配的话,就将源点连一条边到当前匹配的W,再从W连条边到I,I需要拆点,然后将拆点后面的那个点连接到N,从N连接到汇点。所有边的容量都是1。需要注意避免产生重边。然后最大流就是答案。

代码

#include<iostream>
#include<stack>
#include<vector>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#define MAX_V 1500
#define MAX_N 10004
#define INF 2500005
using namespace std;

struct edge{int to,cap,rev;bool isRev;};

vector<edge> G[MAX_N];
int level[MAX_V];
int iter[MAX_V];

void add_edge(int from,int to,int cap) {
    G[from].push_back((edge) {to, cap, G[to].size(),0});
    G[to].push_back((edge) {from, 0, G[from].size() - 1,1});
}

void bfs(int s) {
    memset(level, -1, sizeof(level));
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while (!que.empty()) {
        int v = que.front();
        que.pop();
        for (int i = 0; i < G[v].size(); i++) {
            edge &e = G[v][i];
            if (e.cap > 0 && level[e.to] < 0) {
                level[e.to] = level[v] + 1;
                que.push(e.to);
            }
        }
    }
}

int dfs(int v,int t,int f) {
    if (v == t)return f;
    for (int &i = iter[v]; i < G[v].size(); i++) {
        edge &e = G[v][i];
        if (e.cap > 0 && level[v] < level[e.to]) {
            int d = dfs(e.to, t, min(f, e.cap));
            if (d > 0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t) {
    int flow = 0;
    for (; ;) {
        bfs(s);
        if (level[t] < 0)return flow;
        memset(iter, 0, sizeof(iter));
        int f;
        while ((f = dfs(s, t, INF)) > 0) {
            flow += f;
        }
    }
}

string ss[30];
int n,m;
//int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};

int Hash(int x,int y) {
    return x * m + y;
}

int S=1234;
int T=1313;

bool vis[MAX_V];

void AddEdges(int W,int I,int N) {
    if (!vis[W])
        add_edge(S, W, 1);
    add_edge(W, I, 1);
    add_edge(I + n * m + 5, N, 1);
    if (!vis[N])
        add_edge(N, T, 1);
    vis[W] = vis[N] = 1;
}

int main() {
    cin.sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        cin >> ss[i];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            if (ss[i][j] != ‘I‘)continue;
            add_edge(Hash(i, j), Hash(i, j) + n * m+5, 1);
            int u, v;
            u = j - 1;
            v = j + 1;
            if (u >= 0 && v < m) {
                if (ss[i][u] == ‘N‘ && ss[i][v] == ‘W‘)swap(u, v);
                if (ss[i][u] == ‘W‘ && ss[i][v] == ‘N‘)
                    AddEdges(Hash(i, u), Hash(i, j), Hash(i, v));
            }
            u = i - 1;
            v = i + 1;
            if (u >= 0 && v < n) {
                if (ss[u][j] == ‘N‘ && ss[v][j] == ‘W‘)swap(u, v);
                if (ss[u][j] == ‘W‘ && ss[v][j] == ‘N‘)
                    AddEdges(Hash(u, j), Hash(i, j), Hash(v, j));
            }
            u = j - 1;
            v = i - 1;
            if (u >= 0 && v >= 0) {
                if (ss[i][u] == ‘N‘ && ss[v][j] == ‘W‘)
                    AddEdges(Hash(v, j), Hash(i, j), Hash(i, u));
                if (ss[i][u] == ‘W‘ && ss[v][j] == ‘N‘)
                    AddEdges(Hash(i, u), Hash(i, j), Hash(v, j));
            }
            u = i - 1;
            v = j + 1;
            if (u >= 0 && v < m) {
                if (ss[u][j] == ‘N‘ && ss[i][v] == ‘W‘)
                    AddEdges(Hash(i, v), Hash(i, j), Hash(u, j));
                if (ss[u][j] == ‘W‘ && ss[i][v] == ‘N‘)
                    AddEdges(Hash(u, j), Hash(i, j), Hash(i, v));
            }
            u = j + 1;
            v = i + 1;
            if (u < m && v < n) {
                if (ss[i][u] == ‘N‘ && ss[v][j] == ‘W‘)
                    AddEdges(Hash(v, j), Hash(i, j), Hash(i, u));
                if (ss[i][u] == ‘W‘ && ss[v][j] == ‘N‘)
                    AddEdges(Hash(i, u), Hash(i, j), Hash(v, j));
            }
            u = i + 1;
            v = j - 1;
            if (u < n && v >= 0) {
                if (ss[u][j] == ‘N‘ && ss[i][v] == ‘W‘)
                    AddEdges(Hash(i, v), Hash(i, j), Hash(u, j));
                if (ss[u][j] == ‘W‘ && ss[i][v] == ‘N‘)
                    AddEdges(Hash(u, j), Hash(i, j), Hash(i, v));
            }
        }
    int f = max_flow(S, T);
    cout << f << endl;
    return 0;
}
时间: 2025-01-01 23:12:22

Codeforces Gym 100203I I WIN 最大流的相关文章

Gym - 100203I I WIN 网络流

Gym - 100203I  I WIN 题意:一个n*m的矩阵包含W,I,N三种字符,问相邻的字符最多能组成不重叠的WIN. 思路:比赛的时候没有发现是网络流,,居然一度以为是二分图匹配,,写了一下没过就没改了,,知道了是网络流就好办了.设一个起点一个终点,起点和每个W之间连一条边,N和终点间连一条边,W和I之间连一条边,I和N之间连一条边,不过这里为了避免重复使用同一个I,应改成W到I连一条边,I连一条边到I',再从I'连一条边到N就可以保证最优解了.求一遍最大流即可. 1 #include

Codeforces Gym 100203I I - I WIN 网络流最大流

I - I WINTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87954#problem/I Description Given an n × m rectangular tile with each square marked with one of the letters W, I, and N, find the maximal numb

Codeforces Gym 101190M Mole Tunnels - 费用流

题目传送门 传送门 题目大意 $m$只鼹鼠有$n$个巢穴,$n - 1$条长度为$1$的通道将它们连通且第$i(i > 1)$个巢穴与第$\left\lfloor \frac{i}{2}\right\rfloor$个巢穴连通.第$i$个巢穴在最终时允许$c_i$只醒来的鼹鼠最终停留在这.已知第$i$只鼹鼠在第$p_i$个巢穴睡觉.要求求出对于每个满足$1 \leqslant k \leqslant n$的$k$,如果前$k$只鼹鼠醒来,最小的移动距离的总和. 考虑费用流的建图和暴力做法,把原图的

codeforce Gym 100203I I WIN (网络流)

把'I'拆成容量为1一条边,一个入点一个出点,入点和相邻的'W'连一条容量为1的边,出点和相邻的'N'连一条容量为1,所有的'W'和源点连一条容量为1边,所有的'N'和汇点连一条容量为1的边,表示只能用一次.一发网络流就过了. 写了4000B+的贪心,然并卵 #include<bits/stdc++.h> using namespace std; const int INF = 0x3fffffff; const int maxn = 2142; #define PB push_back st

Codeforces gym Hello 2015 Div1 B and Div2 D

Codeforces gym 100571 problem D Problem 给一个有向图G<V,E>和源点S,边的属性有长度L和颜色C,即E=<L,C>.进行Q次询问,每次给定一个点X,输出S到X的最短路的长度(不存在则输出 -1).但要求S到X的路径中相邻两条边颜色不一样. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 |V|, |E|: [1, 10^5] X, S: [1, |V| ] L: [1, 10^9] |C|

Codeforces gym Hello 2015 Div1 E

Codeforces gym 100570 problem E (一种处理动态最长回文子串问题的方法) Problem 给一个长度为N的字符串S,字符集是'a'-'z'.进行Q次操作,操作分三种.一,修改位置X的字符为C:二,查询以P位置为中心的最长回文子串的长度,并输出:三,查询以P与P+1的中间位置为中心的最长回文子串的长度,并输出. More 第二种操作子串长度为奇数,一定存在:第三种操作子串长度为偶数,若不存在,输出 -1. Limits Time Limit(ms): 4000(1s足

Codeforces gym Hello 2015 Div1 C and Div2 E

Codeforces gym 100570 problem C Codeforces gym 100571 problem E Problem 给一个N行M列的矩阵Ma,进行Q次(Q<=10)查询,每次给定一个K,问有多少子矩阵,满足最大值max - 最小值min <=K. Limits Time Limit(ms): 8000 Memory Limit(MB): 512 N, M: [1, 400] Q: [1, 10] Ma(i, j), K: [1, 10^9] Solution (Th

【模拟】ECNA 2015 I What&#39;s on the Grille? (Codeforces GYM 100825)

题目链接: http://codeforces.com/gym/100825 题目大意: 栅栏密码.给定N(N<=10),密钥为一个N*N的矩阵,'.'代表空格可以看到,'X'代表被遮挡,还有密文字符串S,长度为N*N 每次将这个矩阵顺时针旋转90°,把矩阵中空格对应的位置按照从上到下从左到右的顺序依次填充上密文字符,求最终这个密文字符能否填满N*N的矩阵,能按顺序输出得到的答案,不能输出"invalid grille" 题目思路: [模拟] 直接模拟即可.旋转的坐标公式很好推.

Codeforces gym Hello 2015 Div2 B

Codeforces gym 100571 problem B Problem 设函数F(x),F(1)与F(2)已知,且当 i>=3,F(i)=a*F(i-2)+b*F(i-1).再给一个长度为N的数列A,进行Q次如下操作:每次给一个区间[L, R],对于每个k(L=<k<=R),将A[k]=A[k]+F[k-L+1].最后输出数列A(mod 10^9+7). Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N, Q: [1, 10^