CF 1214 D Treasure Island 网络流

这篇博客介绍了如何利用网络流算法解决CF 1214 D题目的问题,该问题涉及到在一个n×m的网格中,通过改变最少的格子使其无法从起点(1,1)到达终点(n,m)。博主指出,这个问题可以转化为求最小割的最大流问题,并详细阐述了如何构建图、设置边的流量和成本,以及如何执行网络流算法来找到答案。同时提醒注意在实现过程中对某些变量的初始化和边界条件的处理。" 77503770,1450194,七牛云CDN服务详解及常见问题解答,"['CDN服务', '七牛云CDN', '网络加速', '缓存策略', '性能优化']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有一个 n ∗ m n*m nm的格子, 一个人起点 ( 1 , 1 ) (1,1) (1,1), 目的点是 ( n , m ) (n,m) (n,m)可以往右/往下走, #为不能走的点, 问做少把几个.改成#(不能改起点和终点)能让这个人不能走到.
当然最多改2个鸭
最小割就是最大流啊
网络流冲冲冲
把图里的每个格子拆成两个点, 其间的流量就是去掉这个点的代价(1), 当然第一个点和最后一个点代价是inf.
然后每个点的2号向其下/右的点的1号连边, 流量是inf.
然后从起点到终点跑网络流就行了.
注意这样n*m的图, 拆点可以学习ZGQ的函数:

int point1(int i, int j) {
    return i * mm + j;
}
int point2(int i, int j) {
    return i * mm + j + nn * mm;
}

真的强啊

注意自己的板子要初始化n.(当然不是图上的n啊!!)

代码:

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const int maxN = 2200050;
const int maxM = 4200050;

namespace DINIC {
    int n;// 这个n要记得初始化
    int cnt;
    int Head[maxN];
    int Next[maxM << 1];
    int W[maxM << 1];
    int V[maxM << 1];
    int Depth[maxN];
    int cur[maxN];//cur就是记录当前点u循环到了哪一条边
    int s, t;
    void init2() {// 初始化函数记得调用
        cnt = -1;
        memset(Head, -1, sizeof(int) * n);
        memset(Next, -1, sizeof(int) * n);
    }
    void _Add(int u, int v, ll w) {// 不要用
        cnt++;
        Next[cnt] = Head[u];
        Head[u] = cnt;
        V[cnt] = v;
        W[cnt] = w;
    }
    void Add_Edge(int u, int v, int w) {// 用这个
        _Add(u, v, w);
        _Add(v, u, 0);
    }
    int dfs(int u, int flow) {
        if (u == t)
            return flow;
        for (int &i = cur[u]; i != -1; i = Next[i]) {
            //注意这里的&符号,这样i增加的同时也能改变cur[u]的值,达到记录当前弧的目的
            if ((Depth[V[i]] == Depth[u] + 1) && (W[i] != 0)) {
                int di = dfs(V[i], min(flow, W[i]));
                if (di > 0) {
                    W[i] -= di;
                    W[i ^ 1] += di;
                    return di;
                }
            }
        }
        return 0;
    }
    int bfs() {
        queue<int> Q;
        while (!Q.empty())
            Q.pop();
        memset(Depth, 0, sizeof(Depth));
        Depth[s] = 1;
        Q.push(s);
        do {
            int u = Q.front();
            Q.pop();
            for (int i = Head[u]; i != -1; i = Next[i]) {
                if ((Depth[V[i]] == 0) && (W[i] > 0)) {
                    Depth[V[i]] = Depth[u] + 1;
                    Q.push(V[i]);
                }
            }
        } while (!Q.empty());
        if (Depth[t] > 0)
            return 1;
        return 0;
    }

    int Dinic() {
        int Ans = 0;
        while (bfs()) {
            for (int i = 1; i <= n; i++)
                cur[i] = Head[i];
            while (ll d = dfs(s, inf)) {
                Ans += d;
            }
        }
        return Ans;
    }
};
string mp[1123456];
int nn, mm;
int point1(int i, int j) {
    return i * mm + j;
}
int point2(int i, int j) {
    return i * mm + j + nn * mm;
}
void init() {
    using namespace DINIC;
    FAST;
    cin >> nn >> mm;
    for (int i = 0; i < nn; ++i) {
        cin >> mp[i];
    }
    n = point2(nn - 1, mm - 1) + 100;
    init2();
    for (int i = 0; i < nn; ++i) {
        for (int j = 0; j < mm; ++j) {
            if (mp[i][j] == '#')continue;
            if ((i == 0 && j == 0) || (i == nn - 1 && j == mm - 1))
                Add_Edge(point1(i, j), point2(i, j), inf);
            else
                Add_Edge(point1(i, j), point2(i, j), 1);
            if (i + 1 < nn && mp[i + 1][j] != '#')
                Add_Edge(point2(i, j), point1(i + 1, j), inf);
            if (j + 1 < mm && mp[i][j + 1] != '#')
                Add_Edge(point2(i, j), point1(i, j + 1), inf);
        }
    }
    s = point1(0, 0), t = point2(nn - 1, mm - 1);
    int ans = Dinic();
    cout << ans << endl;
}

int main() {
    init();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值