题意

给出一个n*m的矩阵,每个点有不同的花费,初始兔子在B点,你可以通过移除一些点,使得兔子无法到达边界,注意兔子只能上下左右移动。

题解

网络流,注意这种去掉点的套路,一定是拆点。



#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+100;
const ll inf=1e15;

int n,m,c;
ll w[100];
string S[100];
int vis[100][100];
int s,t;
int sx,sy;
int X[4]={1,0,-1,0};
int Y[4]={0,1,0,-1};
ll a[100][100];


struct node {
int u,v,nxt;
ll w;
}edge[maxn<<1];
int head[maxn];
int tot;
void addedge (int u,int v,ll w) {
edge[tot].u=u;
edge[tot].v=v;
edge[tot].w=w;
edge[tot].nxt=head[u];
head[u]=tot++;

edge[tot].u=v;
edge[tot].v=u;
edge[tot].w=0;
edge[tot].nxt=head[v];
head[v]=tot++;
}

ll dep[maxn];
ll inq[maxn];
ll cur[maxn];
ll wjm;
ll maxflow=0;
bool bfs () {
for (int i=0;i<=t;i++) {
cur[i]=head[i];
dep[i]=inf;
inq[i]=0;
}
dep[s]=0;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u=q.front();
q.pop();
inq[u]=0;
for (int i=head[u];i!=-1;i=edge[i].nxt) {
int v=edge[i].v;
if (dep[v]>dep[u]+1&&edge[i].w) {
dep[v]=dep[u]+1;
if (inq[v]==0) {
q.push(v);
inq[v]=1;
}
}
}
}
if (dep[t]!=inf) return 1;
return 0;
}
ll dfs (int u,ll flow) {
ll increase=0;
if (u==t) {
wjm=1;
maxflow+=flow;
return flow;
}
ll used=0;
for (int i=cur[u];i!=-1;i=edge[i].nxt) {
cur[u]=i;
int v=edge[i].v;
if (edge[i].w&&dep[v]==dep[u]+1) {
if (increase=dfs(v,min(flow-used,edge[i].w))) {
used+=increase;
edge[i].w-=increase;
edge[i^1].w+=increase;
if (used==flow) break;
}
}
}
return used;
}
ll Dinic () {
maxflow=0;
while (bfs()) {
wjm=1;
while (wjm==1) {
wjm=0;
dfs(s,inf);
}
}
return maxflow;
}


int Bfs (int sx,int sy) {
queue<pair<int,int> > q;
q.push(make_pair(sx,sy));
vis[sx][sy]=1;
while (q.size()) {
pair<int,int> tt=q.front();
q.pop();
for (int i=0;i<4;i++) {
int tx=tt.first+X[i];
int ty=tt.second+Y[i];
if (tx<1||tx>n||ty<1||ty>m) {
return 0;
}
if (S[tx-1][ty-1]>='a'&&S[tx-1][ty-1]<='z') continue;
if (!vis[tx][ty]) {
q.push(make_pair(tx,ty));
vis[tx][ty]=1;
}
}
}
return 1;
}





int main () {
scanf("%d%d%d",&m,&n,&c);
memset(head,-1,sizeof(head));
for (int i=0;i<n;i++) cin>>S[i];
for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (S[i-1][j-1]=='B') sx=i,sy=j;

//1~n*m为每个点的上点
//n*m+1~n*m*2为每个点的下点
//n*m*2+1为汇点
s=0;
t=n*m*2+1;
for (int i=0;i<c;i++) scanf("%lld",w+i);
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
if (S[i-1][j-1]>='a'&&S[i-1][j-1]<='z')
a[i][j]=w[S[i-1][j-1]-'a'];
else
a[i][j]=inf;
//printf("%d ",a[i][j]);
}
//printf("\n");
}
int ff=Bfs(sx,sy);
if (!ff) {
printf("-1\n");
return 0;
}
addedge(s,(sx-1)*m+sy,inf);
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
addedge((i-1)*m+j,(i-1)*m+j+n*m,a[i][j]);
for (int k=0;k<4;k++) {
int tx=i+X[k];
int ty=j+Y[k];
if (tx<1||tx>n||ty<1||ty>m) {
addedge((i-1)*m+j+n*m,t,inf);
}
else {
addedge((i-1)*m+j+n*m,(tx-1)*m+ty,inf);
}
}
}
}
printf("%lld\n",Dinic());
}