题意
给出一个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(" "); } int ff=Bfs(sx,sy); if (!ff) { printf("-1 "); 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 ",Dinic()); }