题意:有一大块区域,总共 N 行,M 列,所以是 N * M 块小土地,然后土地有高有低,不是高就是低,拖拉机在同样
高度的土地不需要额外花费,如果经过的边是高低土地之间的边,那就要花费 A 元,当然我们也可以把土地垫高或者弄低,
这样就花费 B 元。一块小土地有四个边。让我们求经过所有土地的边,需要的最小花费。
利用最小割 = 最大流。
我们首先要设一个超级源点,超级汇点,
与 S 联通的都是 矮的土地,,与 T 联通的都是高的土地。
然后 相邻的土地之间连两条边 , u -> v 费用为B
v -> u 费用为 B, (我自己也不知道为什么这样建边。)
我们要从 s 到 t ,我们也不知道 v u 是在哪一边,所以都要建边吧。
然后 矮的和 S 建边,这样相当于割断这条边,矮的土地就变成了高的土地。
高的土地也一样,我们割断一条边就相当于投靠了另外一个阵营。
#include <bits/stdc++.h>
using namespace std;
#define mem(x,v) memset(x,v,sizeof(x))
const int INF = 0x3f3f3f3f;
const int NN = 5000;
const int MM = 50000;
const int dx[4] = {-1,1,0,0};
const int dy[4] = {0,0,-1,1};
struct node
{
int u,v,w;
}f[MM];
int N,M,A,B,cnt = -1,s,t;
int head[NN],Next[MM],cur[NN],dep[NN];
char Map[100][100];
void _Add(int u, int v, int w){
cnt++;
Next[cnt] = head[u];
head[u] = cnt;
f[cnt].v = v;
f[cnt].w = w;
return;
}
void Add_edge(int u, int v, int w){
_Add(u,v,w);
_Add(v,u,0);
return;
}
bool bfs(){
queue<int>q;
while(!q.empty()) q.pop();
q.push(s);
mem(dep,0);
dep[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = Next[i]){
int v = f[i].v;
if (dep[v] == 0 && f[i].w > 0){
dep[v] = dep[u] + 1;
if (v == t) return 1;
q.push(v);
}
}
}
//cout<<dep[t]<<endl;
if (dep[t]) return 1;
return 0;
}
int dfs(int u, int flow){
if (u == t || flow == 0) return flow;
for (int& i = cur[u]; i != -1; i = Next[i]){
int v = f[i].v,w = f[i].w;
if (dep[v] >dep[u] && w > 0){
int d = dfs(v,min(flow,w));
if (d){
f[i].w -= d;
f[i^1].w += d;
return d;
}
}
}
return 0;
}
long long Dinic(){
long long ans = 0,d;
while(bfs()){
for (int i = 0; i <= t; i++)
cur[i] = head[i];
while(d = dfs(s,INF))
ans += d;
}
return ans;
}
int main(){
scanf("%d%d%d%d",&N,&M,&A,&B);
s = 0; t = N * M + 1;
for (int i = 0; i < N; i++)
cin>>Map[i];
mem(head,-1); //一开始没有初始化,所以一直错。神TM
for (int i = 0; i < N; i++){
for (int j = 0; j < M; j++){
if (Map[i][j] == '.') Add_edge(0,i*M+j+1,B);
if (Map[i][j] == '#') Add_edge(i*M+j+1,t,B);
for (int k = 0; k < 4; k++){
int x = i + dx[k];
int y = j + dy[k];
if (x >= 0 && y >= 0 && x < N && y < M){
int u = x * M + y + 1;
int v = i * M + j + 1;
Add_edge(v,u,A);
}
}
}
}
long long Ans = 0;
Ans = Dinic();
printf("%I64d\n",Ans);
return 0;
}