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 <iostream>
  2 #include <cstdio>
  3 #include <fstream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <deque>
  7 #include <vector>
  8 #include <queue>
  9 #include <string>
 10 #include <cstring>
 11 #include <map>
 12 #include <stack>
 13 #include <set>
 14 #define LL long long
 15 #define eps 1e-8
 16 #define INF 0x3f3f3f3f
 17 #define MAXN 1005
 18 using namespace std;
 19
 20 struct Edge{
 21     int from, to, cap, flow;
 22     //Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f){};
 23 };
 24 struct Dinic{
 25     int n, m, i, s, t;
 26     Edge e;
 27     vector<Edge> edges;
 28     vector<int> G[MAXN];
 29     int d[MAXN], cur[MAXN];
 30     bool vis[MAXN];
 31     void init(int n){
 32         this->n = n;
 33         for (i = 0; i <= n; i++){
 34             G[i].clear();
 35         }
 36         edges.clear();
 37     }
 38     void AddEdge(int from, int to, int cap){
 39         edges.push_back(Edge{ from, to, cap, 0 });
 40         edges.push_back(Edge{ to, from, 0, 0 });
 41         m = edges.size();
 42         G[from].push_back(m - 2);
 43         G[to].push_back(m - 1);
 44     }
 45     bool BFS(){
 46         memset(vis, 0, sizeof(vis));
 47         queue<int> Q;
 48         Q.push(s);
 49         d[s] = 0;
 50         vis[s] = 1;
 51         while (!Q.empty()){
 52             int x = Q.front();
 53             Q.pop();
 54             for (i = 0; i < G[x].size(); i++){
 55                 Edge& e = edges[G[x][i]];
 56                 if (!vis[e.to] && e.cap > e.flow){
 57                     vis[e.to] = true;
 58                     d[e.to] = d[x] + 1;
 59                     Q.push(e.to);
 60                 }
 61             }
 62         }
 63         return vis[t];
 64     }
 65     int DFS(int x, int a){
 66         if (x == t || a == 0) return a;
 67         int flow = 0, f;
 68         for (int& i = cur[x]; i < G[x].size(); i++){
 69             Edge& e = edges[G[x][i]];
 70             if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0){
 71                 e.flow += f;
 72                 edges[G[x][i] ^ 1].flow -= f;
 73                 flow += f;
 74                 a -= f;
 75                 if (a == 0) break;
 76             }
 77         }
 78         return flow;
 79     }
 80     int MaxFlow(int s, int t, int need){
 81         int flow = 0;
 82         this->s = s;
 83         this->t = t;
 84         while (BFS()){
 85             memset(cur, 0, sizeof(cur));
 86             flow += DFS(s, INF);
 87             if (flow > need) return flow;
 88         }
 89         return flow;
 90     }
 91 };
 92 char a[50][50];
 93 Dinic p;
 94 const int step[4][2] = { 1, 0, 0, 1, -1, 0, 0, -1 };
 95 bool vis[25][25];
 96 int main()
 97 {
 98 #ifndef ONLINE_JUDGE
 99     freopen("in.txt", "r", stdin);
100     //freopen("out.txt", "w", stdout);
101 #endif // OPEN_FILE
102     int n, m;
103     scanf("%d%d", &n, &m);
104     for (int i = 1; i <= n; i++){
105         scanf("%s", a[i] + 1);
106     }
107     int s = 0, t = 2 * n * m + 1;
108     p.init(t);
109     memset(vis, 0, sizeof(vis));
110     for (int i = 1; i <= n; i++){
111         for (int j = 1; j <= m; j++){
112             int u = (i - 1) * m + j;
113             if(a[i][j] == ‘W‘){
114                 p.AddEdge(s, u, 1);
115                 for (int k = 0; k < 4; k++){
116                     int x = i + step[k][0];
117                     int y = j + step[k][1];
118                     if (x < 1 || y < 1 || x > n || y > m) continue;
119                     if (a[x][y] == ‘I‘){
120                         p.AddEdge(u, (x - 1) * m + y, 1);
121                     }
122                 }
123             }
124             else if (a[i][j] == ‘I‘){
125                 int v = u + n * m;
126                 p.AddEdge(u, v, 1);
127                 for (int k = 0; k < 4; k++){
128                     int x = i + step[k][0];
129                     int y = j + step[k][1];
130                     if (x < 1 || y < 1 || x > n || y > m) continue;
131                     if (a[x][y] == ‘N‘){
132                         p.AddEdge(v, (x - 1) * m + y, 1);
133                         if (vis[x][y]) continue;
134                         p.AddEdge((x - 1) * m + y, t, 1);
135                         vis[x][y] = true;
136                     }
137                 }
138             }
139         }
140     }
141     int ans = p.MaxFlow(s, t, INF);
142     printf("%d\n", ans);
143 }
时间: 2024-10-29 19:10:50

Gym - 100203I I WIN 网络流的相关文章

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 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<ve

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

Gym 101128F Sheldon Numbers(网络流)

[题目链接] http://codeforces.com/gym/101128/attachments [题目大意] 给出一张地图,分为高地和低地,高低地的交界线上划有红线, 现在要开小车跨过每条红线,当改变小车开的地形的时候,比如从高地开往低地, 就需要多耗油A单位,也可以花B的耗油量抬高地形或者降低地形, 问跨越所有红线所用的最少耗油量 [题解] 我们发现对于每条红线,我们需要花A去跨越地形或者花B去抬高或者降低地形, 所以我们将不同地形划分为两个集合,构成二分图, 红线左右块连流量为A的边

codeforces gym 100357 J (网络流)

题目大意 有n种物品,m种建筑,p个人. n,m,p∈[1,20] 每种建筑需要若干个若干种物品来建造.每个人打算建造一种建筑,拥有一些物品. 主角需要通过交易来建造自己的建筑,交易的前提是对方用多余的物品来换取自己需要的物品. 询问主角是否能建造成功自己的建筑,并给出方案. 解题分析 超级恶心的读入,而且有一组数据的给出方式里没有逗号,和样例所示不同= = 根据py的性质很容易想到用网络流来做.将每种物品拆成x,y两份. 若主角多了a物品b件,连一条S到物品a,x部流量为b的边. 若主角少了a

UVA 1306 - The K-League(网络流)

UVA 1306 - The K-League 题目链接 题意:n个球队,已经有一些胜负场,现在还有一些场次,你去分配胜负,问每支球队有没有可能获胜 思路:网络流公平分配模型,把场次当作任务,分配给人,然后先贪心,枚举每个人,让这些人能赢的都赢,剩下的去建图,每个源点连向比赛容量为场次,每个比赛连向2个球队,容量无限大,每个球队连向汇点,容量为每个的人的总和减去当前已经赢的,建完图跑一下最大流,然后判断源点流出的是否都满流即可 代码: #include <cstdio> #include &l

CodeForces Gym 100500A A. Poetry Challenge DFS

Problem A. Poetry Challenge Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100500/attachments Description Let’s check another challenge of the IBM ICPC Chill Zone, a poetry challenge. One says a poetry string that starts with a

ZOJ 3348 Schedule(map运用+网络流之最大流)(竞赛问题升级版)

题目地址:ZOJ 3348 仍然是一道竞赛问题的网络流问题,但是这道题再用上次的竞赛建图方法就不行了,5000场比赛,明显会超时,于是需要换种建图思路了.上一道经典竞赛问题戳这里 上一道的胜负转换是利用专门给比赛建一个点,通过对比赛双方的流向来控制胜负关系,这里的建图方法更加巧妙(膜拜想出这个方法的大牛...),是先假设其中一方获胜,用mp[a][b]来表示a赢b的次数,将a与b连边,权值为mp[a][b],这样的话,前面的假设就仅仅只是假设而已,因为在这里,如果a的流量流向了b,说明a的胜利果

ZOJ3508_The War(网络流最大流)

解题报告 http://blog.csdn.net/juncoder/article/details/38235609 题目传送门 题意: N个士兵,M个武器,每个士兵能接受的武器重量范围是[minw,maxw] 思路: 本来以为二分图可以的,(看错数据范围了,,,)贪心好像可以. scf说网络流可以缩点. 建图方式:源点和士兵连一条线,每个士兵与[1,1000]的武器重量连边,[1,1000]与汇点连线,容量是武器i的数量 #include <queue> #include <cstd