原题链接: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. 水题:UVa213- Message Decoding

    Message Decoding Some message encoding schemes require that an encoded message be sent in two parts. ...

  2. list_add_tail()双向链表实现分析

    struct list_head { struct list_head *next, *prev; }; list_add_tail(&buf->vb.queue, &vid-& ...

  3. android自动化测试之Monkey--从参数讲解、脚本制作到实战技巧

    视频: http://v.youku.com/v_show/id_XODcyMjM1MDA4.html?from=y1.2-1-87.4.4-1.1-1-2-3 PPT: http://www.doc ...

  4. [转载]关于typedef的用法总结

    不管实在C还是C++代码中,typedef这个词都不少见,当然出现频率较高的还是在C代码中.typedef与#define有些相似,但更多 的是不同,特别是在一些复杂的用法上,就完全不同了,看了网上一 ...

  5. c#中利用“|”运算组合多项

    前几天看到一段代码 int i = GetCount(para1 | para2); 咋一看有些莫名奇妙,怎么传参的时候带了个或运算,其实这里面是有讲究的,查阅了各方资料,QQ群里赖着大牛问,才搞明白 ...

  6. An entity cannot be annotated with both @Entity and @MappedSuperclass: com.example1.demo1.Entity.User错误

    项目问SpringDataJpa项目,在运行的过程中出现的以下错误: Caused by: org.hibernate.AnnotationException: An entity cannot be ...

  7. 控制台窗口和powershell运行服务会卡住的解决办法

    之前使用nodejs做了一个简单的web服务,通过控制台窗口运行,通过浏览器访问发现有时候浏览器等很久数据都加载不出来,以为是代码有问题,后来发现是控制台卡住了,按一下enter键就好了,当时百度了一 ...

  8. AtCoder Regular Contest 083

    C - Sugar Water Time limit : 3sec / Memory limit : 256MB Score : 300 points Problem Statement Snuke ...

  9. list 类

    题外:len = sizeof(a)/sizeof(a[0]); 求出数组长度 1.list是一种以双向链表方式实现的一种顺序容器.list容器中,存放元素的存储单元可以是连续的也可以是不连续的. 2 ...

  10. Educational Codeforces Round 19 A+B+C+E!

    A. k-Factorization 题意:将n分解成k个大于1的数相乘的形式.如果无法分解输出-1. 思路:先打个素因子表,然后暴力判,注意最后跳出的条件. int len,a[N],b[N]; v ...