GYM101982E Cops And Roobers (网络流+拆点)

题意

给出一个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());
}

 

posted @ 2020-11-07 11:12  zlc0405  阅读(84)  评论(0编辑  收藏  举报