BZOJ2150 部落战争 【带上下界最小流】
题目链接
题解
复习:
带上下界网络流两种写法:
- 不建\(T->S\)的\(INF\)的边,即不考虑源汇点,先求出此时超级源汇的最大流,即无源汇下最大的自我调整,再加入该边,求超级源汇最大流增加的流量
- 先求出【或观察出】\(S->T\)的最大流,记为\(tot\),然后撤销流量,再建立\(T->S\),求出超级源汇最大流\(f\),答案为\(tot - f\)
两者本质一样,但后者在\(S->T\)最大流确定的情况下,可以增加效率
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 5005,maxm = 3000005,INF = 0x3f3f3f3f;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
return flag ? out : -out;
}
char sq[55];
int X[] = {1,1},Y[] = {-1,1};
int N,M,R,C,id[55][55],tot;
int S,T,q[maxn],head,tail,cur[maxn];
int now,used[maxn],vis[maxn],d[maxn];
int h[maxn],ne = 1;
struct EDGE{int to,nxt,f;}ed[maxm];
inline void build(int u,int v,int f){
ed[++ne] = (EDGE){v,h[u],f}; h[u] = ne;
ed[++ne] = (EDGE){u,h[v],0}; h[v] = ne;
}
bool bfs(int S,int T){
q[head = tail = 0] = S; vis[S] = ++now;
int u;
while (head <= tail){
u = q[head++];
Redge(u) if (ed[k].f && vis[to = ed[k].to] != now){
d[to] = d[u] + 1;
vis[to] = now;
q[++tail] = to;
if (to == T) return true;
}
}
return false;
}
int dfs(int u,int minf,int T){
if (u == T || !minf) return minf;
int f,flow = 0,to;
if (used[u] != now) used[u] = now,cur[u] = h[u];
for (int& k = cur[u]; k; k = ed[k].nxt)
if (vis[to = ed[k].to] == now && d[to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f),T))){
ed[k].f -= f; ed[k ^ 1].f += f;
flow += f; minf -= f;
if (!minf) break;
}
return flow;
}
int main(){
N = read(); M = read(); R = read(); C = read();
REP(i,N){
scanf("%s",sq + 1);
REP(j,M) if (sq[j] == '.') id[i][j] = ++tot;
}
S = (tot << 1) + 1; T = S + 1;
REP(i,N) REP(j,M){
if (!id[i][j]) continue;
int x,y,u = id[i][j];
build(S,u + tot,1); build(u,T,1);
for (int k = 0; k < 2; k++){
x = i + X[k] * R;
y = j + Y[k] * C;
if (x < 1 || y < 1 || x > N || y > M || !id[x][y]) continue;
build(u + tot,id[x][y],1);
}
if (R != C){
for (int k = 0; k < 2; k++){
x = i + X[k] * C;
y = j + Y[k] * R;
if (x < 1 || y < 1 || x > N || y > M || !id[x][y]) continue;
build(u + tot,id[x][y],1);
}
}
}
int ans = tot;
while (bfs(S,T)) ans -= dfs(S,INF,T);
printf("%d\n",ans);
return 0;
}