首先按照题意,将所有的最外面一层的边都填上草,记录相应的花费。然后建立相应的流网络,将题目化解为求最小割的问题。在建立流网络的时候要将源点到最外层每一条边上的点的权值设置为无穷大,也就是说源点代表的是草的集合,无穷大代表对应的另外的一个点是不能够分离出去的,对于其他的点以及代表着洞的点到相应的目标点的权值也就是题目输入的数据的值,然后对于内部的各个点之间建立权值为b的边,也就代表着建立相应栅栏的代价,然后利用最小流算法求解即可,题目中是h*w,一开始搞错了,所以后面用了个swap,具体实现见如下代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
using namespace std;
class Edge{
public:
int from, to, cap, flow;
Edge(int fr, int t, int c, int fl) :from(fr), to(t), cap(c), flow(fl){}
};
int dx[] = { 0, 0, 1, -1 };
int dy[] = { 1, -1, 0, 0 };
class Solve{
public:
int w, h, d, f, b;
vector<Edge> edge;
vector<int> G[2510];
vector<string> area;
int ans;
const int Inf = 0x3f3f3f3f;
void addEdge(int from,int to,int cap,int flow){
edge.push_back(Edge(from, to, cap, flow));
edge.push_back(Edge(to, from, 0, 0));
int m = edge.size();
G[from].push_back(m-2);
G[to].push_back(m - 1);
}
void Init(){
edge.clear();
area.clear();
ans = 0;
for (int i = 0; i < 2510; i++) G[i].clear();
cin >> w >> h >> d >> f >> b;
swap(w,h);
for (int i = 0; i < w; i++){
string t;
cin >> t;
area.push_back(t);
}
for (int i = 0; i < w; i++){
if (area[i][0] == '.'){
area[i][0] = '#';
ans += f;
}
if (area[i][h - 1] == '.'){
area[i][h - 1] = '#';
ans += f;
}
}
for (int j = 0; j < h; j++){
if (area[0][j] == '.'){
area[0][j] = '#';
ans += f;
}
if (area[w - 1][j] == '.'){
area[w - 1][j] = '#';
ans += f;
}
}
for (int i = 0; i < w; i++){
for (int j = 0; j < h; j++){
if (i == 0 || i == w - 1 || j == 0 || j == h - 1){
addEdge(0, i*h + j + 1, Inf, 0);
}
else{
if (area[i][j] == '#'){
addEdge(0, i*h + j + 1, d, 0);
}
else{//'.'
addEdge(i*h + j + 1, w*h + 1, f, 0);
}
}
for (int k = 0; k < 4; k++){
int newi = i + dx[k];
int newj = j + dy[k];
if (newi >= 0 && newi < w&&newj >= 0 && newj < h){
addEdge(i*h+j+1,newi*h+newj+1,b,0);
}
}
}
}
}
int MaxFlow(){
int flow = 0;
int end = w*h + 1;
while (true){
int Flow[2510];
int parent[2510];
memset(Flow, 0, sizeof(Flow));
Flow[0] = Inf;
queue<int> q;
q.push(0);
while (!q.empty()){
int id = q.front();
q.pop();
for (int i = 0; i < G[id].size(); i++){
int ide = G[id][i];
int to = edge[ide].to;
if (!Flow[to] && edge[ide].cap>edge[ide].flow){
Flow[to] = min(Flow[id], edge[ide].cap - edge[ide].flow);
q.push(to);
parent[to] = ide;
}
}
if (Flow[end]) break;
}
if (!Flow[end]) break;
flow += Flow[end];
for (int i = end; i != 0; i = edge[parent[i]].from){
edge[parent[i]].flow += Flow[end];
edge[parent[i] ^ 1].flow -= Flow[end];
}
}
return flow;
}
int Deal(){
Init();
return ans+MaxFlow();
}
};
int main(){
Solve a;
int T;
cin >> T;
while (T--){
int res=a.Deal();
cout << res << endl;
}
return 0;
}