全图最小割(Stoer-Wagner算法)

来源:互联网 发布:三维激光扫描数据 编辑:程序博客网 时间:2024/05/21 16:59

全图最小割大致是来解决这样一类问题:
给定一个n个点m条边的无向图,每条边有一个最大流量,给定一个源点s,求以哪个点作为汇点可以使整个图的最大流最小。

思路分两步(引用网上的普遍解析):
一:找到S - T的最小割Mincut,其中S 和 T为最后并入集合的两个点。
1,初始化数组vis 和 wage;
2,遍历所有不在集合且没有被合并的点,找到最大wage值的点Next,并记录Mincut、S和T;
3,Next并入集合,叠加与Next相连的所有点(不在集合 且 没有被合并),更新这些点的wage值;
4,重复操作2和3一共N次 或者 找不到新的Next值时 跳出,返回Mincut;
二、找全局最小割ans,需要重复第一步N-1次,因为每次合并一个点,最多合并N-1个点;
1,每次对返回的Mincut,更新ans = min(ans, Mincut),当然ans为0时,说明图不连通;
2,把点T合并到S点,操作有:对 所有没有被合并的点j,Map[S][j] += Map[T][j]。

模板:

int Map[MAXN][MAXN];//从(1,1)开始bool vis[MAXN];//是否已并入集合int wage[MAXN];//记录每个点的连通度bool In[MAXN];//该点是否已经合并到其它点int N, M;void getMap(){    memset(Map, 0, sizeof(Map));    int a, b, c;    for(int i = 0; i < M; i++)    {        scanf("%d%d%d", &a, &b, &c);        Map[a][b] += c;        Map[b][a] += c;    }}int S, T;//记录每次找s-t割  所遍历的最后两个点int work(){    int Mincut;//每一步找到的s-t割    memset(wage, 0, sizeof(wage));    memset(vis, false, sizeof(vis));    int Next;    for(int i = 1; i <= N; i++)    {        int Max = -INF;        for(int j = 1; j <= N; j++)        {            if(!In[j] && !vis[j] && Max < wage[j])//找最大的wage值            {                Next = j;                Max = wage[j];            }        }        if(Next == T) break;//找不到点 图本身不连通        vis[Next] = true;//标记 已经并入集合        Mincut = Max;//每次更新        S = T, T = Next;// 记录前、后点        for(int j = 1; j <= N; j++)//继续找不在集合 且 没有被合并过的点        {            if(In[j] || vis[j]) continue;            wage[j] += Map[Next][j];//累加 连通度        }    }    return Mincut;}int Stoer_wagner(){    memset(In, false, sizeof(In));    int ans = INF;    for(int i = 0; i < N-1; i++)    {        ans = min(ans, work());        if(ans == 0) return 0;//本身不连通        In[T] = true;        for(int j = 1; j <= N; j++)//把T点合并到S点        {            if(In[j]) continue;//已经合并            Map[S][j] += Map[T][j];            Map[j][S] += Map[j][T];        }    }    return ans;}int main(){    while(scanf("%d%d", &N, &M) != EOF)    {        getMap();        printf("%d\n", Stoer_wagner());    }    return 0;}