poj2914-Minimum Cut-Stoer-Wagner算法

本文详细介绍了一种求解图中最小割问题的有效算法。通过逐步解释关键概念如割、最小割及s-t最小割,并配以具体案例分析,帮助读者深入理解最小割算法的工作原理及其应用场景。

割:在一个图GVE)中V是点集,E是边集。在E中去掉一个边集C使得GVE-C)不连通,C就是图GVE)的一个割;

最小割:GVE)的所有割中,边权总和最小的割就是最小割。

 

G的任意s-t最小割Min-Cst):

st是途中的两个点且边(st)∈E(即st之间存在一条边)。如果G的最小割CutG分成MN两个点集

①:如果sMtNMin-Cst= Cut(不讨论)

②:如果stM(或者stN)则Min-Cst<= Cut

 

我们来定义一个Contract(a,b)操作,即把ab两个点合并,表示为删除节点b,把b的节点信息添加到a

如下图是做了Contract5,6

最小割 <wbr>Stoer-Wagner <wbr>算法

最小割 <wbr>Stoer-Wagner <wbr>算法

对于所点vw(v,5)+=w(v,6)

 

s-t最小割的方法

定义w(A,x) = ∑w(v[i],x)v[i]∈A

定义Ax为在x前加入A的所有点的集合(不包括x

1.令集合A={a}aV中任意点

2.选取V-A中的w(A,x)最大的点x加入集合

3.|A|=|V|,结束,否则更新w(A,x),转到2

令倒数第二个加入A的点为s,最后一个加入A的点为t,则s-t最小割为w(At,t)

 

Poj (pku) 2914 Minimum Cut

的第三个case为例,图为

 

 

 

 

 

 

 

 

最小割 <wbr>Stoer-Wagner <wbr>算法

GVE

我们设法维护这样的一个w[],初始化为0

我们把V-A中的点中w[i]最大的点找出来加入A集合;

V-A直到为空

w[]的情况如下

w[i]

0

1

2

3

4

5

6

7

初始值

0

0

0

0

0

0

0

0

A=A{0}

---

1

1

1

1

0

0

0

A=A{1}

 

---

2

2

1

0

0

0

A=A{2}

 

 

---

3

1

0

0

0

A=A{3}

 

 

 

---

1

0

0

1

A=A{4}

 

 

 

 

---

1

1

2

A=A{7}

 

 

 

 

 

2

2

---

A=A{5}

 

 

 

 

 

---

3

 

A=A{6}

 

 

 

 

 

 

---

 

 

每次w[i]+=(i,a)的权值aA

记录最后加入A的节点为t=6,倒数第二个加入A的为s=5,则s-t的最小割就为w[s],在图中体现出来的意思就是5-6的最小割为w[s]=3

然后我们做Contract(s,t)操作,得到下图

最小割 <wbr>Stoer-Wagner <wbr>算法

G(V’,E’)

重复上述操作

 

 

 

w[i]

0

1

2

3

4

5

7

初始值

0

0

0

0

0

0

0

A=A{0}

---

1

1

1

1

0

0

A=A{1}

 

---

2

2

1

0

0

A=A{2}

 

 

---

3

1

0

0

A=A{3}

 

 

 

---

1

0

1

A=A{4}

 

 

 

 

---

2

2

A=A{5}

 

 

 

 

 

---

4

A=A{7}

 

 

 

 

 

 

---

s=5t=7    s-t最小割是4

Contract(s,t)得到

最小割 <wbr>Stoer-Wagner <wbr>算法

 

 

w[i]

0

1

2

3

4

5

初始值

0

0

0

0

0

0

A=A{0}

---

1

1

1

1

0

A=A{1}

 

---

2

2

1

0

A=A{2}

 

 

---

3

1

0

A=A{3}

 

 

 

---

1

1

A=A{4}

 

 

 

 

---

4

A=A{5}

 

 

 

 

 

---

s=4t=5    s-t最小割是4

Contract(s,t)得到

最小割 <wbr>Stoer-Wagner <wbr>算法


 

 

w[i]

0

1

2

3

4

初始值

0

0

0

0

0

A=A{0}

---

1

1

1

1

A=A{1}

 

---

2

2

1

A=A{2}

 

 

---

3

1

A=A{3}

 

 

 

---

2

A=A{4}

 

 

 

 

---

s=3t=4    s-t最小割是2,(此时已经得出答案,以下省略)


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int w=501;
int map[w][w],set[w],visit[w],value[w],minc;
void search(int &s,int &t,int n)
{
    int i,j,m,k;
    for(i=0;i<=n;i++)
    {
        value[i]=0;
        visit[i]=0;
    }
    for(i=0;i<n;i++)
    {
        m=-inf;
        for(j=0;j<n;j++)
        {
            if(!set[j]&&!visit[j]&&m<value[j])
            {
                m=value[j];
                k=j;
            }
        }
        visit[k]=1;
        if(t==k) {minc=value[k];return ;}
        s=t;t=k;
        for(j=0;j<n;j++)
        {
            if(!visit[j]&&!set[j])
            {
                value[j]+=map[t][j];
            }
        }
    }
    minc=value[t];

}
int mincut(int n)
{
    int i,j,s,t,ans=inf;
    memset(set,0,sizeof(set));
    for(i=0;i<n-1;i++)
    {
        s=t=-1;
        search(s,t,n);
        set[t]=1;
        ans=min(ans,minc);
        for(j=0;j<n;j++)
        {
            map[s][j]+=map[t][j];
            map[j][s]+=map[j][t];
        }
    }
return ans;
}
int main()
{
    int n,m,i,j,k,t;
    while(~scanf("%d%d",&n,&m))
    {
        memset(map,0,sizeof(map));
        while(m--)
        {
            scanf("%d%d%d",&i,&j,&k);
            map[i][j]+=k;
            map[j][i]+=k;
        }
        printf("%d\n",mincut(n));
    }
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值