BZOJ1163&BZOJ1339[Baltic2008]Mafia——最小割

题目描述

匪徒准备从一个车站转移毒品到另一个车站,警方准备进行布控. 对于每个车站进行布控都需要一定的代价,现在警
方希望使用最小的代价控制一些车站,使得去掉这些车站后,匪徒无法从原定的初始点到达目标点

输入

第一行输入N,M代表车站的总个数,及有多少条双向边连接它们. 
2<=n<=200 , 1 <=m<=20000. 
第二行给出两个数a,b,代表匪徒的出发点及目标点.1<=a,b<=N,a<>b. 
再下来有N行,给出对第i个车站进行布控所需要的Money,其不超过10 000 000 
再下来M行,用于描述图的结构.

输出

最少需要多少Money

样例输入

5 6
5 3
2
4
8
3
10
1 5
1 2
2 4
4 5
2 3
3 4

样例输出

5
 
 
  题意就是让删除一些点使得源点和汇点不联通且删除点权和最小,将每个点拆成一个入点和一个出点,两点间边权为原来点的点权,然后建双向边,就把问题转换成了求网络最小割。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int next[6000001];
int to[6000001];
int val[6000001];
int head[6000001];
int tot=1;
int q[6000001];
int n,m;
int S,T;
int x,y;
int k1,k2;
int ans;
int d[6000001];
const int INF=0x3f3f3f3f;
void add(int x,int y,int v)
{
    tot++;
    next[tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    val[tot]=v;
    tot++;
    next[tot]=head[y];
    head[y]=tot;
    to[tot]=x;
    val[tot]=0;
}
bool bfs(int S,int T)
{
    int r=0;
    int l=0;
    memset(d,-1,sizeof(d));
    q[r++]=S;
    d[S]=0;
    while(l<r)
    {
        int now=q[l];
        for(int i=head[now];i;i=next[i])
        {
            if(d[to[i]]==-1&&val[i]!=0)
            {
                d[to[i]]=d[now]+1;
                q[r++]=to[i];
            }
        }
        l++;
    }
    if(d[T]==-1)
    {
        return false;
    }
    else
    {
        return true;
    }
}
int dfs(int x,int flow)
{
    if(x==T)
    {
        return flow;
    }
    int now_flow;
    int used=0;
    for(int i=head[x];i;i=next[i])
    {
        if(d[to[i]]==d[x]+1&&val[i]!=0)
        {
            now_flow=dfs(to[i],min(flow-used,val[i]));
            val[i]-=now_flow;
            val[i^1]+=now_flow;
            used+=now_flow;
            if(now_flow==flow)
            {
                return flow;
            }
        }
    }
    if(used==0)
    {
        d[x]=-1;
    }
    return used;
}
void dinic()
{
    while(bfs(S,T)==true)
    {
        ans+=dfs(S,0x3f3f3f);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%d%d",&k1,&k2);
    S=k1;
    T=n+k2;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        add(i,n+i,x);
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(n+x,y,INF);
        add(n+y,x,INF);
    }
    dinic();
    printf("%d",ans);
    return 0;
}
posted @ 2018-07-13 07:49  The_Virtuoso  阅读(190)  评论(0编辑  收藏  举报