UVa1376/LA3661 Animal Run
- 题目链接
- 题意
- 输入格式
- 输出格式
- 分析
- AC 代码
题目链接
UVA - 1376 Animal Run
题意
由于控制程序出了 bug,动物园的笼子无缘无故被打开,所有动物展开了一次大逃亡。整个城市是一个网格,另外每个单位方格都有一条从左上到右下的对角线,其中动物园在左上角,动物们的目的地是右下角。所有道路(即网格的边和对角线)都是双向的。
每条道路上都有一个正整数权值,代表拦截这条边所需要的工作人员数,如下图所示。你的任务是派尽量少的工作人员,使动物无法从动物园走到目的地(动物只能经过没有被拦截的边)。
输入格式
输入包含多组数据。每组数据第一行为两个整数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;
}