嘘~ 正在从服务器偷取页面 . . .

洛谷P4001 [ICPC-Beijing 2006] 狼抓兔子 题解


洛谷P4001 [ICPC-Beijing 2006] 狼抓兔子 题解

题目链接:P4001 [ICPC-Beijing 2006] 狼抓兔子

题意

现在小朋友们最喜欢的"喜羊羊与灰太狼"。话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

左上角点为 \((1,1)\),右下角点为 \((N,M)\)(上图中 \(N=3\)\(M=4\))。有以下三种类型的道路:

  1. \((x,y)\rightleftharpoons(x+1,y)\)

  2. \((x,y)\rightleftharpoons(x,y+1)\)

  3. \((x,y)\rightleftharpoons(x+1,y+1)\)

道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的。左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角 \((1,1)\) 的窝里,现在它们要跑到右下角 \((N,M)\) 的窝中去,狼王开始伏击这些兔子。当然为了保险起见,如果一条道路上最多通过的兔子数为 \(K\),狼王需要安排同样数量的 \(K\) 只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦。

输入格式

第一行两个整数 \(N,M\),表示网格的大小。

接下来分三部分。

第一部分共 \(N\) 行,每行 \(M-1\) 个数,表示横向道路的权值。

第二部分共 \(N-1\) 行,每行 \(M\) 个数,表示纵向道路的权值。

第三部分共 \(N-1\) 行,每行 \(M-1\) 个数,表示斜向道路的权值。

输出格式

输出一个整数,表示参与伏击的狼的最小数量。

数据范围

保证 \(3 \leq N,M \leq 1000\),所有道路的权值均为不超过 \(10^6\) 的正整数。

本题正解不是网络流,而是对偶图最短路。

下图就是样例的对偶图,其中绿色的点和 \(s,t\) 称为对偶图,点之间的边权就是横跨的那条边的边权。

可以证明,对偶图的最短路就是原图的最小割。

时间复杂度 \(\mathcal{O}(nm \log nm)\)

代码:(需要仔细想想)

#include <bits/stdc++.h>
using namespace std;
// #define int long long
#define INF 0x3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e3 + 15))

int n, m, pos = 1, head[N][N], d[N][N]; char vis[N][N];
struct Edge { int v1, v2, w, next; } e[N * N * 2 * 2];
void addEdge(int u1, int u2, int v1, int v2, int w) {
    e[++pos] = {v1, v2, w, head[u1][u2]}; head[u1][u2] = pos;
}
struct node { int u1, u2, dis; } ;
bool operator<(node a, node b) { return a.dis > b.dis; }
priority_queue<node> q;
void Dijkstra(int s1, int s2)
{
    memset(d, 0x3f, sizeof(d)); d[s1][s2] = 0; 
    for(q.push({s1, s2, 0}); !q.empty(); )
    {
        auto [u1, u2, _] = q.top(); q.pop();
        if(vis[u1][u2]) continue; else vis[u1][u2] = true;
        for(int i = head[u1][u2]; i; i = e[i].next)
        {
            int v1 = e[i].v1, v2 = e[i].v2, w = e[i].w;
            if(d[v1][v2] > d[u1][u2] + w)
            {
                d[v1][v2] = d[u1][u2] + w;
                if(!vis[v1][v2]) q.push({v1, v2, d[v1][v2]});
            }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m;
    if(n == 1)
    {
        int res = INF;
        for(int i = 1, x; i < m; i++) { cin >> x; down(res, x); }
        cout << res << '\n'; return 0;
    }
    if(m == 1)
    {
        int res = INF;
        for(int i = 1, x; i < n; i++) { cin >> x; down(res, x); }
        cout << res << '\n'; return 0;
    }
    for(int i = 1, w; i <= n; i++)
        for(int j = 1; j < m; j++)
        {
            cin >> w;
            if(i == 1) {
                addEdge(i, j * 2, n + 1, m + 1, w);
                addEdge(n + 1, m + 1, i, j * 2, w);
            }else if(i == n) {
                addEdge(i - 1, j * 2 - 1, n, m, w);
                addEdge(n, m, i - 1, j * 2 - 1, w);
            }else {
                addEdge(i - 1, j * 2 - 1, i, j * 2, w);
                addEdge(i, j * 2, i - 1, j * 2 - 1, w);
            }
        }
    for(int i = 1, w; i < n; i++)
        for(int j = 1; j <= m; j++)
        {
            cin >> w;
            if(j == 1) {
                addEdge(n, m, i, j * 2 - 1, w);
                addEdge(i, j * 2 - 1, n, m, w);
            }else if(j == m) {
                addEdge(n + 1, m + 1, i, (m - 1) * 2, w);
                addEdge(i, (m - 1) * 2, n + 1, m + 1, w);
            }else {
                addEdge(i, (j - 1) * 2, i, (j - 1) * 2 + 1, w);
                addEdge(i, (j - 1) * 2 + 1, i, (j - 1) * 2, w);
            }
        }
    for(int i = 1, w; i < n; i++)
        for(int j = 1; j < m; j++)
        {
            cin >> w;
            addEdge(i, j * 2 - 1, i, j * 2, w);
            addEdge(i, j * 2, i, j * 2 - 1, w);
        }
    Dijkstra(n, m); cout << d[n + 1][m + 1] << '\n'; // 起点 (n,m) 终点 (n + 1, m + 1)
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/ilr0re7n


题外话


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录