第二节 最小割

最大权闭合子图

定义:有一个有向图,每一个点都有一个权值(可以为正或负或 0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图。

解法:

这个问题可以转化为最小割问题,用网络流解决。
从源点 S 向每个正权点连一条容量为权值的边,每个负权点向汇点 T 连一条容量为权值的绝对值的边,有向图原来的边容量全部为无限大。求它的最小割,割掉后,与源点s连通的点构成最大权闭合子图,权值为 正权值之和 - 最小割

可以理解为,所有点要么和 S 相连,要么和 T 相连(没必要全割掉)。割掉 Si 的边,表示不选择 i 点作为子图的点;割掉 iT 的边,表示选择 i 点为子图的点。

例题:P2762 太空飞行计划问题

题目大意:

m 个实验,每个实验只可以进行一次,但会获得相应的奖金,有 n 个仪器,每个实验都需要一定的仪器,每个仪器可以运用于多个实验,但需要一定的价值,问奖金与代价的差的最大值是多少?

分析:

每个实验有正权值,仪器有负权值,从实验向所需要的仪器连边,问题即转化为求最大权闭合子图。

平面图最小割

例题:P4001 [ICPC-Beijing 2006]狼抓兔子

题目大意:

给一个如下的平面图,求最小割。

第一行两个整数 N,M,表示网格的大小。接下来分三部分。第一部分共 N 行,每行 M-1 个数,表示横向道路的权值。第二部分共 N-1 行,每行 M 个数,表示纵向道路的权值。第三部分共 N-1 行,每行 M-1 个数,表示斜向道路的权值。

分析:

平面图的最小割等于其对偶图的最短路:我们先连接原先的起点和终点,然后对于每对相邻的块连边,权值和原图中相邻的边一样。连接 ST 所形成的两块,其中的两点之间最短路即为答案。
此题注意特判 n=1 的情况,应直接连接 ST

int n, m, S, T;
int id(int x, int y, int op) {
    return (x - 1) * (m - 1) * 2 + 2 * y - op;
}

int main(int argc, const char * argv[]) {
    scanf("%d%d", &n, &m);
    S = (n - 1) * (m - 1) * 2 + 1; T = S + 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1, w; j < m; j++) {
            scanf("%d", &w);
            if (n == 1) {
                add(S, T, w); add(T, S, w);
                continue;
            }
            int u = id(i, j, 0), v = id(i - 1, j, 1);
            if (i == 1) {
                add(u, T, w); add(T, u, w);
            }
            if (i == n) {
                add(v, S, w); add(S, v, w);
            }
            if (i != 1 && i != n) {
                add(u, v, w); add(v, u, w);
            }
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = 1, w; j <= m; j++) {
            scanf("%d", &w);
            if (m == 1) {
                add(S, T, w); add(T, S, w);
                continue;
            }
            int u = id(i, j, 1), v = id(i, j - 1, 0);
            if (j == 1) {
                add(u, S, w); add(S, u, w);
            }
            if (j == m) {
                add(v, T, w); add(T, v, w);
            }
            if (j != 1 && j != m) {
                add(u, v, w); add(v, u, w);
            }
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = 1, w; j < m; j++) {
            scanf("%d", &w);
            int u = id(i, j, 0), v = id(i, j, 1);
            add(u, v, w); add(v, u, w);
        }
    }
    Dijkstra(T);
    printf("%d\n", dis[S]);
    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇