HDU 3491

题意如下,有多个小偷 从 s 点逃往 h 点,有 N 个城市, m 条路,每个城市最少需要 x 个 警察驻守才能防守住,问最少需要多少个警察才能把全部小偷堵住。。。

 

 

最小割。。。一眼就能看出来。转化最大流,因为每个城市要 X 个警察才能守住,我们就对其进行拆点,有了上一题经验,既然求最小割,我们把题目里的边容量设成 INF 来防止被割,然后跑一边最大流就可以成功的 割点了。。

 

 

 

换了个板子。。。感觉神清气爽。。。。

 

 

 

 

 

 

 

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
int head[maxn],cnt;
int h[maxn];
struct node 
{
    int to;
    int cap;
    int next;
}edge[2 * maxn];
void init()
{
    memset(head, -1, sizeof(head));
    cnt = 0;
}
void add(int u, int v, int cap)
{
        edge[cnt].to = v, edge[cnt].cap = cap, edge[cnt].next = head[u], head[u] = cnt++;
        edge[cnt].to = u, edge[cnt].cap =  0 , edge[cnt].next = head[v], head[v] = cnt++;
}
bool bfs(int s, int t)
{
        memset(h, 0, sizeof(h));
        queue<int>q;
        h[s] = 1;
        q.push(s);
        while (q.size())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i != -1; i = edge[i].next)
            {
                int v = edge[i].to;
                if (edge[i].cap > 0 && h[v] < 0)
                {
                    h[v] = h[u] + 1;
                    q.push(v);
                }
            }
        }
        return h[t];
}
int dfs(int u, int t, int num)
{
    if (u == t)
        return num;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (edge[i].cap > 0 && h[u] + 1 == h[v])
        {
            int d = dfs(v, t, min(num, edge[i].cap));
            if (d > 0)
            {
                edge[i].cap -= d;
                edge[i ^ 1].cap += d;
                return d;
            }
        }
    }
    h[u] = -1;
    return 0;
}
int dinic(int s, int t)
{
    int sum = 0, num;
    while (bfs(s, t))
    {
        while(num = dfs(s, t, INF) && num > 0)
        {
            sum += num;
        }
    }
    return sum;
}
int T, a, b;
int n, m, s, t;
int main()
{
    cin >> T;
    while (T--)
    {
        init();
        cin >> n >> m >> s >> t;
        add(s, s + n, INF);
        add(t, t + n, INF);
        for (int i = 1; i <= n; i++)
        {
            cin >> a;
            add(i, i + n, a);// 拆点
        }
        for (int i = 1; i <= m; i++)
        {
            cin >> a >> b;
            add(a + n, b, INF);
            add(b + n, a, INF);
        }
        cout << dinic(s, t + n) << endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值