hdu 4289 Control 最小割最大流

http://acm.hdu.edu.cn/showproblem.php?pid=4289

题意:

有N个城市 M条无向边 有一些恐怖分子要从某一城市到另一城市 打算在某些城市安放一些SA 去抓住他 但若在某个城市安放SA需要一定费用 求一个集合使每个到达终点的路线肯定会经过其中一个点,而这个集合里面每个点都安放了SA,这样就能找到所有的恐怖分子,求该集合使费用最小。

思路:

网络流的题目做的还太少,对于这类题目还是不太敏感,没想到拆点建图。。。。

题目意思是求一个s-t割,求最小的费用肯定要求最小割了,又由于最小割等于最大流,所以我们只要用最大流求解即可,而这里建图是关键,这里将每个点拆成两个点(i ,i + n)然后i与i + n 的权值为该点小费,反向边为0 ,(x,y)则建立(x + n,y) (y + n,x)权值为inf 这里他们的反向边都为0;跑一边最大流算法就好了。。

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 10000007
#define M 100007
#define N 407
using namespace std;
//freopen("din.txt","r",stdin);

struct node{
    int v,w;
    int next;
}g[N*N];
int head[N],ct;
int q[maxn],level[N];
int n,m;
void init(){
    ct = 0;
    CL(head,-1);
}

void add(int u,int v,int w){
    g[ct].v = v;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;

    g[ct].v = u;
    g[ct].w = 0;
    g[ct].next = head[v];
    head[v] = ct++;
}
bool layer(int s,int e){
    int l = 0;
    int r = 0;
    CL(level,-1); level[s] = 0;
    q[r] = s;
    while (l <= r){
        int u = q[l++];
        for (int i = head[u]; i != -1; i = g[i].next){
            int v = g[i].v;
            if (level[v] == -1 && g[i].w > 0){
                level[v] = level[u] + 1;
                if (v == e) return true;
                q[++r] = v;
            }
        }
    }
    return false;
}
int find(int s,int e){
    int top = 1;
    int i;
    int ans = 0;
    while (top){
        int u = (top == 1 ? s : g[q[top - 1]].v);
        if (u == e){
            int MIN = inf,pos;
            for (i = 1; i < top; ++i){
                int tp = q[i];
                if (g[tp].w < MIN){
                    MIN = g[tp].w;
                    pos = i;
                }
            }
            for (i = 1; i < top; ++i){
                int tp = q[i];
                g[tp].w -= MIN;
                g[tp^1].w += MIN;
            }
            ans += MIN;
            top = pos - 1;
        }
        else{
            for (i = head[u]; i != -1; i = g[i].next){
                int v = g[i].v;
                if (level[v] == level[u] + 1 && g[i].w > 0){
                    q[top++] = i;
                    break;
                }
            }
        }
        if (i == -1){
            top--;
            level[u] = -1;
        }
    }
    return ans;
}
int dinic(int s,int e){
    int ans = 0;
    while (layer(s,e)){
        ans += find(s,e);
    }
    return ans;
}
int main(){
    //freopen("din.txt","r",stdin);
    int i;
    int s,e,val;
    int x,y;
    while (~scanf("%d%d",&n,&m)){
        init();
        scanf("%d%d",&s,&e);
        e = e + n;
        for (i = 1; i <= n; ++i){
            scanf("%d",&val);
            add(i,i + n,val);
        }
        for (i = 0; i < m; ++i){
            scanf("%d%d",&x,&y);
            add(x + n,y,inf);
            add(y + n,x,inf);
        }
        printf("%d\n",dinic(s,e));
    }
    return 0;
}

 

 

 

转载于:https://www.cnblogs.com/E-star/archive/2012/09/18/2691441.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值