UVALive - 3661 Animal Run (平面图+最小割+对偶图+最短路)

题目大意:有很多只小动物要从左上角跑到右下角,给出每条线路所需的人手,问至少需要多少人手,才能将所有动物抓住

解题思路:最小割,就是最小割,但是用最大流处理不了,边太多了

具体可以参考算法合集之《浅析最大最小定理在信息学竞赛中的应用》

知道了这个后,这题估计就可以解了

给出我的建图方式

将每一个小三角形从左往右,从上到下依次编号为1-2-3。。

每行的同一个三角行的编号差就是2 * (m - 1)

如图

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1111 * 1111 * 3;
#define INF 0x3f3f3f3f

struct Edge{
    int to, next, dist;
}E[N<<2];

struct Node {
    int id, val;
    Node(int id, int val): id(id), val(val) {}
    bool operator < (const Node &a) const {
        return val > a.val;
    }
};

int head[N], d[N];
int tot, source, sink, n, m;
bool inq[N];

void AddEdge(int from, int to, int dist) {
    E[tot].to = to;
    E[tot].dist = dist;
    E[tot].next = head[from];
    head[from] = tot++;
}

void init() {
    memset(head, -1, sizeof(head));
    tot = 0;
    source = 2 * (m - 1) * (n - 1) + 2;
    sink = source - 1;

    int u, v, d;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m - 1; j++) {
            scanf("%d", &d);
            if (i == 1) {
                u = j * 2;
                AddEdge(sink, u, d);
                AddEdge(u, sink, d);
            }
            else if(i == n) {
                u = 2 * (m - 1) * (i - 2) + 2 * (j - 1) + 1;
                AddEdge(source, u, d);
                AddEdge(u, source, d);
            }
            else {
                u = 2 * (m - 1) * (i - 2) + 2 * (j - 1) + 1;
                v = u + 2 * (m - 1) + 1;
                AddEdge(u, v, d);
                AddEdge(v, u, d);
            }
        }

    for (int i = 1; i <= n - 1; i++)
        for (int j = 1; j <= m; j++) {
            scanf("%d", &d);
            if (j == 1) {
                u = 2 * (m - 1) * (i - 1) + 1;
                AddEdge(u, source, d);
                AddEdge(source, u, d);
            }
            else if(j == m) {
                u = 2 * (m - 1) * i;
                AddEdge(u, sink, d);
                AddEdge(sink, u, d);
            }
            else {
                u = 2 * (m - 1) * (i - 1) + 2 * (j - 1);
                v = u + 1;
                AddEdge(u, v, d);
                AddEdge(v, u, d);
            }
        }

    for (int i = 1; i <= n - 1; i++)
        for (int j = 1; j <= m - 1; j++) {
            scanf("%d", &d);
            u = 2 * (m - 1) * (i - 1) + 2 * (j - 1) + 1;
            v = u + 1;
            AddEdge(u, v, d);
            AddEdge(v, u, d);
        }
}

void BFS() {
    priority_queue<Node> q;
    memset(inq, 0, sizeof(inq));
    for (int i = 1; i <= sink; i++)
        d[i] = INF;
    int u;
    d[source] = 0;
    q.push(Node(source, 0));
    while (!q.empty()) {
        Node cur = q.top();
        q.pop();

        int u = cur.id;
        if (inq[u])
            continue;
        inq[u] = true;;
        for (int i = head[u]; i != -1; i = E[i].next) {
            int v = E[i].to;
            if (d[v] > d[u] + E[i].dist) {
                d[v] = d[u] + E[i].dist;
                q.push(Node(v, d[v]));
            }
        }
    }
}

int main() {
    int cas = 1;
    while (scanf("%d%d", &n, &m) != EOF && n + m) {
        init();
        BFS();
        printf("Case %d: Minimum = %d\n", cas++, d[sink]);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-21 12:43:32

UVALive - 3661 Animal Run (平面图+最小割+对偶图+最短路)的相关文章

平面图最小割 对偶图

平面图最小割 对偶图: 平面图G的性质: (1)满足n个点,m条边,f个面 f = m - n + 2; (2)存在与其对应的对偶图G*; 对偶图:将原图中每个面变成一个点,外边界的无限大的面看成一个点,后连线即成对偶图: G的面数等于G*的点数,边数相等: 详解请看 最大最小定理(平面图最小割 对偶图)周冬 对于平面图的最大流(最小割)只需转化为对偶图,直接跑最短路即可: ps:觉得建图是最复杂的,各种RE(边数就是原来的边数,只是点数变成了原来的面数,,不注意就RE了):还有现在行数列数都变

[bzoj1001][BeiJing2006]狼抓兔子-题解[平面图最小割转最短路]/[Dinic求最小割]

Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路

【Algorithm】平面图最小割转最短路

杭电上碰巧有几道求最小割的题目,用网络流解超时.通过离散数学中的一些知识可以将平面图最小割转化为最短路径,通过最短路解提高效率.这个转化过程很简单,但是很巧妙,详细内容可以参考<浅析最大最小定理在信息学竞赛中的应用>. 1. [HDU] 3870 Catch the Theves有一个网格拓扑,每条边都表示有$A_{ij}$个小偷,现在希望对其中一条边部署警察,使得小偷不可能偷到右下角的财宝.求至少需要多少个警察?这题是个挺有实际意义的题目,基本思路也很简单.因为题目给定小偷都从左上角出发向右

【BZOJ2007】【Noi2010】海拔 平面图最小割转最短路

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43280891"); } 题解:这个模型很水,不需要极角序神马转对偶图,直接乱搞就行. 然后目的是把图割开,那么只需要跑S->T最短路就行. 要做平面图转对偶图不妨去这篇. [BZOJ2965]保护古迹 平面图转对偶图,暴力,网络流 还有就是某人

HDU3870 Catch the Theves(平面图最小割转最短路)

题目大概说给一个n×n的方格,边有权值,问从求(1,1)到(n,n)的最小割. 点达到了160000个,直接最大流不好.这题的图是平面图,求最小割可以转化成求其对偶图的最短路,来更高效地求解: 首先源点汇点间新加一条边,然后构造其对偶图: 面作为对偶图的点:而源点到汇点之间新加的边划分出来的两个面分别作为对偶图的源点和汇点 如果两个面之间有边则两个面在对偶图对应的点连边,权值为原来的边权:去掉对偶图源点和汇点之间边 这样可以发现,对偶图的源点到汇点的一条路径就对应这原图的源点到汇点的一个割边集,

hdu 3870(平面图最小割转最短路)

Catch the Theves Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65768/32768 K (Java/Others)Total Submission(s): 1640    Accepted Submission(s): 514 Problem Description A group of thieves is approaching a museum in the country of zjsxzy,now t

【bzoj2007】[Noi2010]海拔 最小割+对偶图+最短路

题目描述 YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主干道上两个相邻的交叉路口.下图为一张YT市的地图(n = 2),城市被划分为2×2个区域,包括3×3个交叉路口和12条双向道路. 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期间YT市每条道路两个方向的人流量,即在高峰期间沿着

【平面图最小割】BZOJ1001- [BeiJing2006]狼抓兔子

[题目大意]左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的.开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,如果一条道路上最多通过的兔子数为K,需要同样数量的K只狼伏击,求封锁道路的最小狼数. [思路]显然这是最小

【平面图最小割】BZOJ2007-[NOI2010]海拔

[题目大意] 城市被东西向和南北向的主干道划分为n×n个区域,包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路.现得到了每天每条道路两个方向的人流量.每一个交叉路口都有海拔,每向上爬h的高度,就需要消耗h的体力.如果是下坡的话,则不需要耗费体力.城市西北角的交叉路口海拔为0,东南角的交叉路口海拔为1.现在知道每条路两个方向的人流量,在最理想的情况下(即你可以任意假设其他路口的海拔高度),求每天所有人爬坡所消耗的总体力和的最小值. [思路] 显然是一个平面图最小割,最基础的平面图最