原题链接: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(),});
G[to].push_back((edge) {from, , G[from].size() - ,});
} void bfs(int s) {
memset(level, -, sizeof(level));
queue<int> que;
level[s] = ;
que.push(s);
while (!que.empty()) {
int v = que.front();
que.pop();
for (int i = ; i < G[v].size(); i++) {
edge &e = G[v][i];
if (e.cap > && level[e.to] < ) {
level[e.to] = level[v] + ;
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 > && level[v] < level[e.to]) {
int d = dfs(e.to, t, min(f, e.cap));
if (d > ) {
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
return ;
} int max_flow(int s,int t) {
int flow = ;
for (; ;) {
bfs(s);
if (level[t] < )return flow;
memset(iter, , sizeof(iter));
int f;
while ((f = dfs(s, t, INF)) > ) {
flow += f;
}
}
} string ss[];
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=;
int T=; bool vis[MAX_V]; void AddEdges(int W,int I,int N) {
if (!vis[W])
add_edge(S, W, );
add_edge(W, I, );
add_edge(I + n * m + , N, );
if (!vis[N])
add_edge(N, T, );
vis[W] = vis[N] = ;
} int main() {
cin.sync_with_stdio(false);
cin >> n >> m;
for (int i = ; i < n; i++)
cin >> ss[i];
for (int i = ; i < n; i++)
for (int j = ; j < m; j++) {
if (ss[i][j] != 'I')continue;
add_edge(Hash(i, j), Hash(i, j) + n * m+, );
int u, v;
u = j - ;
v = j + ;
if (u >= && 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 - ;
v = i + ;
if (u >= && 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 - ;
v = i - ;
if (u >= && v >= ) {
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 - ;
v = j + ;
if (u >= && 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 + ;
v = i + ;
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 + ;
v = j - ;
if (u < n && v >= ) {
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 ;
}

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

  1. Gym - 100203I I WIN 网络流

    Gym - 100203I  I WIN 题意:一个n*m的矩阵包含W,I,N三种字符,问相邻的字符最多能组成不重叠的WIN. 思路:比赛的时候没有发现是网络流,,居然一度以为是二分图匹配,,写了一下 ...

  2. Codeforces Gym 101190M Mole Tunnels - 费用流

    题目传送门 传送门 题目大意 $m$只鼹鼠有$n$个巢穴,$n - 1$条长度为$1$的通道将它们连通且第$i(i > 1)$个巢穴与第$\left\lfloor \frac{i}{2}\rig ...

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

    I - I WINTime Limit: 2 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.acti ...

  4. codeforce Gym 100203I I WIN (网络流)

    把'I'拆成容量为1一条边,一个入点一个出点,入点和相邻的'W'连一条容量为1的边,出点和相邻的'N'连一条容量为1,所有的'W'和源点连一条容量为1边,所有的'N'和汇点连一条容量为1的边,表示只能 ...

  5. Codeforces Gym 101252D&&floyd判圈算法学习笔记

    一句话题意:x0=1,xi+1=(Axi+xi%B)%C,如果x序列中存在最早的两个相同的元素,输出第二次出现的位置,若在2e7内无解则输出-1. 题解:都不到100天就AFO了才来学这floyd判圈 ...

  6. Codeforces Gym 101623A - 动态规划

    题目传送门 传送门 题目大意 给定一个长度为$n$的序列,要求划分成最少的段数,然后将这些段排序使得新序列单调不减. 考虑将相邻的相等的数缩成一个数. 假设没有分成了$n$段,考虑最少能够减少多少划分 ...

  7. 【Codeforces Gym 100725K】Key Insertion

    Codeforces Gym 100725K 题意:给定一个初始全0的序列,然后给\(n\)个查询,每一次调用\(Insert(L_i,i)\),其中\(Insert(L,K)\)表示在第L位插入K, ...

  8. Codeforces gym 101343 J.Husam and the Broken Present 2【状压dp】

     2017 JUST Programming Contest 2.0 题目链接:Codeforces gym 101343 J.Husam and the Broken Present 2 J. Hu ...

  9. codeforces gym 100553I

    codeforces gym 100553I solution 令a[i]表示位置i的船的编号 研究可以发现,应是从中间开始,往两边跳.... 于是就是一个点往两边的最长下降子序列之和减一 魔改树状数 ...

随机推荐

  1. 纯虚函数(pure virtual function )和抽象类(abstract base class)

    函数体=0的虚函数称为“纯虚函数”.包含纯虚函数的类称为“抽象类” #include <string> class Animal // This Animal is an abstract ...

  2. STM32——PWM基本知识及配置过程

    将通用定时器分为四个部分: 1,选择时钟 2,时基电路 3,输入捕获 4,输出比较 本节定时器PWM输出主要涉及到定时器框图右下方部分,即输出比较部分 和上一讲相同,时基时钟来源于内部默认时钟 对此有 ...

  3. 库函数的使用:POJ1488-TEX Quotes(getline()的使用)

    TEX Quotes Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9385 Description TEX is a type ...

  4. Java中的数据类型和引用

    JAVA数据类型分primitive数据类型和引用数据类型. Java中的primitive数据类型分为四类八种.primitive也不知道怎么翻译比较贴切, 暂且叫他基本数据类型吧, 其实直接从英文 ...

  5. 算法学习记录-排序——插入排序(Insertion Sort)

    插入排序: 在<算法导论>中是这样描述的 这是一个对少量元素进行排序的有效算法.插入排序的工作机理与打牌时候,整理手中的牌做法差不多. 在开始摸牌时,我们的左手是空的,牌面朝下放在桌子上. ...

  6. selenium - 常用浏览器操作方法

    常用浏览器操作 (1)初始化浏览器会话: from selenium import webdriver driver = webdriver.Chrome() (2)浏览器最大化操作: driver. ...

  7. Python面试题(练习二)

    1.用Python实现一个二分查找的函数. data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def ...

  8. 实施生成树 STP 高级

    一.生成树协议的演化 生成树协议可以识别防止二层环路 本节介绍每VLAN快速生成树增强版 PVRST+   和多生成树MST   如何配置协议   以及配置生成树系诶稳定性机制 1.生成树协议的演化 ...

  9. 用Python表达对Android的想法

    组员:喻航,张子东 视频:点我 #DISCARD ANDROID TODAY! import turtle import turtle as gui #setting turtle.screensiz ...

  10. 精通CSS高级Web标准解决方案(2-2 可视化格式模型之定位概述)

    视觉格式化模型 块级元素(块框).行内元素(行内框),可以使用display改变生成的框的类型,display:block让行内元素(比如<a>)表现的跟块级元素一样,display:no ...