UVa1376/LA3661 Animal Run

题目链接

   UVA - 1376 Animal Run

题意

   由于控制程序出了 bug,动物园的笼子无缘无故被打开,所有动物展开了一次大逃亡。整个城市是一个网格,另外每个单位方格都有一条从左上到右下的对角线,其中动物园在左上角,动物们的目的地是右下角。所有道路(即网格的边和对角线)都是双向的。
   每条道路上都有一个正整数权值,代表拦截这条边所需要的工作人员数,如下图所示。你的任务是派尽量少的工作人员,使动物无法从动物园走到目的地(动物只能经过没有被拦截的边)。Animal Run

输入格式

   输入包含多组数据。每组数据第一行为两个整数n 和m(3≤n,m≤1 000),即网格的行数和列数。以下n 行每行m-1个整数,即拦截每条横边所需的人数。以下n-1行每行有m个整数,即拦截每条竖边所需的人数。以下n-1行每行m-1个整数,表示拦截每条对角线边所需的人数。上述边的排列顺序为从上到下从左到右。所有权值均为不超过 1 0 6 10^6 106的正整数。输入结束标志为n=m=0。输入文件大小约为16MB。

输出格式

   对于每组数据,输出需要派遣的工作人员总数。

分析

   求平面图的最小割,但本题数据大,如果直接跑最大流估计会tle/mle。
   利用对偶图,求平面图最小割可转化成求对偶图最短路。
   转化成对偶图的办法参见:最小割之平面图转最短路对偶图对于平面图最小割的求解
   先将原s和t连一条边,这样会多出来一个面,叫做附加面,将这个附加面作为对偶图的 s ∗ s* s,将无限面作为对偶图的 t ∗ t* t s ∗ s* s t ∗ t* t以及原图的每个面构成对偶图的顶点,某两个面如果共边,则他们之间连一条边。注意 s ∗ s* s t ∗ t* t的边要删除,这样就构建好了对偶图。求原图的最小割就转化成了求 s ∗ s* s t ∗ t* t的最短路。
对偶图

AC 代码

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

#define N 1002
int d[2*N*N], f[2*N*N], m, n, kase = 0; struct edge {int v, w;}; vector<edge> g[2*N*N];
struct node {
    int d, u;
    bool operator< (const node& rhs) const {
        return d>rhs.d;
    }
};

void solve() {
    int t = 2*(m-1)*(n-1)+1;
    for (int i=0; i<=t; ++i) g[i].clear();
    for (int i=0; i<n; ++i) for (int j=1; j<m; ++j) {
        int u = i<n-1 ? 2*(i*(m-1)+j) : t, v = i ? 2*((i-1)*(m-1)+j)-1 : 0, w; cin >> w;
        g[u].push_back({v, w}); g[v].push_back({u, w});
    }
    for (int i=1; i<n; ++i) for (int j=0; j<m; ++j) {
        int u = j ? 2*((i-1)*(m-1)+j) : t, v = j<m-1 ? 2*((i-1)*(m-1)+j)+1 : 0, w; cin >> w;
        g[u].push_back({v, w}); g[v].push_back({u, w});
    }
    for (int i=1; i<n; ++i) for (int j=1; j<m; ++j) {
        int u = 2*((i-1)*(m-1)+j), v = u-1, w; cin >> w;
        g[u].push_back({v, w}); g[v].push_back({u, w});
    }
    memset(d, 0x7f, sizeof(d)); memset(f, 0, sizeof(f));
    d[0] = 0; priority_queue<node> q; q.push({0, 0});
    while (!q.empty()) {
        int u = q.top().u; q.pop();
        if (u == t) break;
        if (f[u]) continue;
        f[u] = 1;
        for (int i=g[u].size()-1; i>=0; --i) {
            int v = g[u][i].v, d1 = d[u] + g[u][i].w;
            if (d[v] > d1) d[v] = d1, q.push({d[v], v});
        }
    }
    cout << "Case " << ++kase << ": Minimum = " << d[t] << endl;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    while (cin >> n >> m && (n || m)) solve();
    return 0;
}
  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值