BZOJ2150 部落战争 【带上下界最小流】

题目链接

BZOJ2150

题解

复习:
带上下界网络流两种写法:

  1. 不建\(T->S\)\(INF\)的边,即不考虑源汇点,先求出此时超级源汇的最大流,即无源汇下最大的自我调整,再加入该边,求超级源汇最大流增加的流量
  2. 先求出【或观察出】\(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;
}

posted @ 2018-07-13 14:46  Mychael  阅读(176)  评论(0编辑  收藏  举报