uva 1277 Cops and Thieves(完成阻击所需要的最少人数)

传送门:uva 1277 Cops and Thieves

题意:一个犯罪团伙打算去偷一家美术馆。 警察决定派 K 个人堵住所有从匪窝通向美术
馆的道路,不过他们只能驻守在沿途顶点处而不能在匪窝或美术馆,且每个点都
有一个需要警察驻守的最低人数 Ri。 问警察能否完成任务。 (2 < N <= 100, 1 < M <=10000)

思路:我们所要做的就是割掉一些边使得不能从S->T,除了起点和终点之外,其余点拆成两个点,u->u’,流量为a[u]

#include<bits/stdc++.h>
using namespace std;
#define INF 1e6
const int maxn=100410;
const int MAXM=101000;
int head[maxn],tot,cur[maxn];
struct Edge{
    int to,next,cap,flow;
}e[MAXM];
int d[maxn],gap[maxn],N,S[MAXM];

void init(int n){
    memset(head,-1,sizeof(head));
    tot=0;
    N=n;
}

void addedge(int from,int to,int w){
    e[tot].to=to,e[tot].next=head[from];
    e[tot].cap=w,e[tot].flow=0;
    head[from]=tot++;
    e[tot].to=from,e[tot].next=head[to];
    e[tot].cap=0,e[tot].flow=0;
    head[to]=tot++;
}

void bfs(int st){
    memset(d,-1,sizeof(d));
    memset(gap,0,sizeof(gap));
    d[st]=0,gap[0]=1;
    queue<int>Q;
    Q.push(st);
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(d[v]!=-1)
                continue;
            d[v]=d[u]+1;
            gap[d[v]]++;
            Q.push(v);
        }
    }
}

int sap(int st,int ed){
    memcpy(cur,head,sizeof(head));
    bfs(ed);
    int u=st,top=0,ans=0;
    while(d[st]<N){
        if(u==ed){
            int Min=INF,ind;
            for(int i=0;i<top;i++){
                if(Min>e[S[i]].cap-e[S[i]].flow){
                    Min=e[S[i]].cap-e[S[i]].flow;
                    ind=i;
                }
            }
            for(int i=0;i<top;i++){
                e[S[i]].flow+=Min;
                e[S[i]^1].flow-=Min;
            }
            top=ind;
            u=e[S[top]^1].to;
            ans+=Min;
        }
        bool flag=false;
        int v;
        for(int i=cur[u];i!=-1;i=e[i].next){
            v=e[i].to;
            if(e[i].cap>e[i].flow&&d[v]+1==d[u]){
                flag=true;
                cur[u]=i;
                break;
            }
        }
        if(flag){
            S[top++]=cur[u];
            u=v;
            continue;
        }
        int Min=N;
        for(int i=head[u];i!=-1;i=e[i].next){
            v=e[i].to;
            if(e[i].cap>e[i].flow&&d[v]<Min){
                Min=d[v];
                cur[u]=i;
            }
        }
        gap[d[u]]--;
        if(gap[d[u]]==0)
            return ans;
        d[u]=Min+1;
        gap[d[u]]++;
        if(u!=st)
            u=e[S[--top]^1].to;
    }
    return ans;
}
int a[maxn];

int main(){
    int n,m,s,t,k;
    while(scanf("%d%d%d%d%d",&k,&n,&m,&t,&s)!=EOF){
        init(2*n+2);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(i!=s&&i!=t)
                addedge(i,i+n,a[i]);
        }
        int flag=0,u,v;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            if(u==s)
                addedge(u,v,INF);
            else
                addedge(u+n,v,INF);
            if(v==s)
                addedge(v,u,INF);
            else
                addedge(v+n,u,INF);
        }
        //printf("%d\n",sap(s,t));
        if(s==t||sap(s,t)>k)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值