POJ 2914 - Minimum Cut - 全局最小割,Stoer-Wagner算法

题目大意:给定一个N个点、M条边的无向带权图,边的权值均为正整数。若要使它变成非连通图,需要移除的边总权值最小是多少?

N≤500,图中不存在自环,但可能有重边(这里题意没交代清楚)。

Stoer-Wagner算法裸题。英文维基:https://en.wikipedia.org/wiki/Stoer%E2%80%93Wagner_algorithm

该算法的思想之一是:对于一个无向连通图,选定某两点s,t,以及该图的一个s-t割C,则“C是该图的全局最小割”是“C是s-t的最小割”的充分不必要条件。

也就是说,如果我们求得了某两点s-t的最小割C,那么全局最小割要么就是C,要么就是另一个让s,t保持连通的割。因此我们可以在得到s-t最小割之后,将这两个节点合并,然后继续求另外某两点的最小割。

合并节点的方法:对于s,t以外的每个节点u,设边(s,u)的权值为v1(如果该边不存在则v1=0),边(t,u)的权值为v2,那么合并后的新节点与u之间连一条边,权值为v1+v2(当然如果v1=0且v2=0则不用连这条边,反正权值为0的边可以随便删)。

该算法的流程为:

def MinCutPhase(a)
    点集S ← a
    while |S| < 当前图中点的个数
        记节点u与S中所有节点之间边的权值之和为w(u),选取不属于S且w(u)最大的节点u0
        将u0加入S
    y = 最后一个加入S的节点
    x = 倒数第二个加入S的节点
    合并点x,y
    return 合并前的w(y)

def MinCut()
    ans = +∞
    while 图中点的个数 > 1
        任选某个点a
        ans = min(ans, MinCutPhase(a))
    return ans

可以证明在MinCutPhase过程中,w(y)就是x-y最小割的总权值(详见维基,说实话我也看不懂 ̄□ ̄)。

求w(u)的过程和最小生成树的Prim算法很类似。维护一个cost数组,对于每个新加入S的节点,更新与它相连的节点的cost值。

时间复杂度:单次MinCutPhase过程的复杂度与Prim算法相同。优化前为O(N^2),如果用邻接表+堆优化,可以将复杂度降到O(M + N logN)。

MinCutPhase过程共执行了O(N)次,因此总的复杂度为O(N^3)或O(MN + N^2 logN)。

O(N^3)的AC代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <climits>
  5
  6 using namespace std;
  7
  8 const int maxN = 500 + 5;
  9
 10 int dist[maxN][maxN]; //edge (u, v) does not exist if dist[u][v] == 0
 11 int cost[maxN];
 12 bool erased[maxN]; //whether a vertex is erased after merging
 13 bool vis[maxN]; //whether a vertex is visited during minCutPhase process
 14 int N, M;
 15
 16 bool input()
 17 {
 18     if (scanf("%d%d", &N, &M) == EOF)
 19         return false;
 20
 21     memset(dist, 0, sizeof(dist));
 22     for (int u, v, w, i = 0; i < M; i++)
 23     {
 24         scanf("%d%d%d", &u, &v, &w);
 25         dist[u][v] = (dist[v][u] += w);
 26     }
 27     return true;
 28 }
 29
 30 ///@brief: merge u and v, let dist[u][i] += dist[v][i], dist[v][i] = 0; (i.e. "erase" node v)
 31 void mergeVertex(int u, int v)
 32 {
 33     for (int i = 0; i < N; i++)
 34     {
 35         dist[i][u] = (dist[u][i] += dist[v][i]);
 36         dist[v][i] = dist[i][v] = 0;
 37     }
 38     erased[v] = true;
 39 }
 40
 41 ///@brief: get the minimum s-t cut, and merge s and t
 42 ///@param remN: number of remaining vertices
 43 int minCutPhase(int remN)
 44 {
 45     memset(vis, 0, sizeof(vis));
 46     memset(cost, 0, sizeof(cost));
 47
 48     int cur = static_cast<int>(find(erased, erased + N, false) - erased); //find a non-erased node
 49     int pre = cur;
 50     vis[cur] = true;
 51
 52     for (int i = 1; i < remN; i++) //repeat (remN - 1) times
 53     {
 54         for (int to = 0; to < N; to++)
 55             cost[to] += dist[cur][to];
 56
 57         int maxCost = 0;
 58         int maxCostVertex = 0;
 59         for (int j = 0; j < N; j++)
 60         {
 61             if (!vis[j] && cost[j] > maxCost)
 62             {
 63                 maxCost = cost[j];
 64                 maxCostVertex = j;
 65             }
 66         }
 67
 68         if (maxCost == 0) //not updated at all, indicating that the graph is not connected
 69             return 0;
 70
 71         pre = cur;
 72         cur = maxCostVertex;
 73         vis[cur] = true;
 74     }
 75
 76     mergeVertex(pre, cur);
 77     return cost[cur];
 78 }
 79
 80 int minCut()
 81 {
 82     memset(erased, 0, sizeof(erased));
 83
 84     int ans = INT_MAX;
 85     for (int remN = N; remN > 1; --remN)
 86     {
 87         int t = minCutPhase(remN);
 88         if (t == 0)
 89             return 0;
 90         ans = min(ans, t);
 91     }
 92     return ans;
 93 }
 94
 95 int main()
 96 {
 97     while (input())
 98         printf("%d\n", minCut());
 99     return 0;
100 }

( G , w , a ) {\displaystyle (G,w,a)}


          |

        V

          |

        >
        1

    {\displaystyle |V|>1}


       MinimumCutPhase

        (
        G
        ,
        w
        ,
        a
        )

    {\displaystyle (G,w,a)}


       if the cut-of-the-phase is lighter than the current minimum cut
           then store the cut-of-the-phase as the current minimum cut

原文地址:https://www.cnblogs.com/Onlynagesha/p/8453824.html

时间: 2024-11-09 04:39:10

POJ 2914 - Minimum Cut - 全局最小割,Stoer-Wagner算法的相关文章

POJ 2914 Minimum Cut 全局最小割

裸的全局最小割了吧 有重边,用邻接矩阵的时候要小心 #include<iostream> #include<cstdio> #include<bitset> #include<cstring> #define MOD 1000000007 #define maxn 509 using namespace std; int a[590][590],wage[maxn],in[maxn],vis[maxn]; int n,x,y,v; int find(int&

poj 2914 Minimum Cut 无向图最小边割

题意: 求无向图的全局最小边割. 分析: stoer-wagner模板. 代码: //poj 2914 //sep9 #include <iostream> using namespace std; const int maxN=512; int g[maxN][maxN]; int b[maxN],dist[maxN]; int n,m; int Min_Cut_Phase(int ph,int &x,int &y) { int i,j,t; t=1; b[1]=ph; fo

POJ 2914 Minimum Cut 最小割算法题解

最标准的最小割算法应用题目. 核心思想就是缩边:先缩小最大的边,然后缩小次大的边,依此缩小 基础算法:Prime最小生成树算法 不过本题测试的数据好像怪怪的,同样的算法时间运行会差别很大,而且一样的代码替换,居然会WA.系统出错的几率很小,难倒测试系统本题会有错误? 懒得继续测试这道题的系统了,反正算法正确,AC. #include <stdio.h> #include <string.h> #include <limits.h> const int MAX_N = 5

POJ 2914 Minimum Cut

无向图最小割,Stoer Wanger算法.先找了个模板,日后再学习吧... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 555 #define inf 1<<30 int v[MAXN],dist[MAXN]; int map[MAXN][MAXN]; bool vis[MA

图的全局最小割的Stoer-Wagner算法及例题

Stoer-Wagner算法基本思想:如果能求出图中某两个顶点之间的最小割,更新答案后合并这两个顶点继续求最小割,到最后就得到答案. 算法步骤: ------------------------------------------------------------------------------------------------------------------------- (1)首先初始化,设最小割ans = INF                                

POJ 2914 Minimum Cut (全局最小割)

[题目链接] http://poj.org/problem?id=2914 [题目大意] 求出一个最小边割集,使得图不连通 [题解] 利用stoerwagner算法直接求出全局最小割,即答案. [代码(递归)] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int INF=0x3f3f3f3f; const int MAX_N=510; int v

POJ 2914 Minimum Cut 最小割图论

Description Given an undirected graph, in which two vertices can be connected by multiple edges, what is the size of the minimum cut of the graph? i.e. how many edges must be removed at least to disconnect the graph into two subgraphs? Input Input co

POJ2914 Minimum Cut【全局最小割】【Stoer-Wangner】

题目链接: http://poj.org/problem?id=2914 题目大意: 提一个无向有重边的图,有重边的边权累加起来,求全局最小割. 思路: 一个无向连通图,去掉一个边集可以使其变成两个连通分量则这个边集就是割集.最小割 集当然就是权和最小的割集. 这是一个最简单的全局最小割模板题.直接套上模板就可以了.来说说Stoer-Wangner算 法吧. Stoer-Wangner算法: 对于图中的任意两个顶点u和v,若u,v属于最小割的同一个集合中,那么僵顶点u和顶点 v合并后并不影响图的

全局最小割 学习总结

全局最小割的意思是在一个无向图中任取S和T,求最小割的最小值 还有一种描述是删掉无向图中的边使得其不连通的最小代价 当然,这种题目可以用分治+最小割来求解 但是时间复杂度大约在O(n^4)左右 有一种更好的求解方法可以在O(n^3)的时间复杂度内求解 做法是这样的: 首先对于图中任意两点S->T 要么S和T不在一个集合里时是答案,答案显然是S和T的最小割 否则S和T在一个集合里,我们可以将S和T缩成一个点,不难证明这样是等效的 我们模拟这个过程,每次任取S和T跑最小割,时间复杂度大概跟分治+最小