POJ-2914 Minimum Cut 无源无汇又向图中的最小割

  题目链接:http://poj.org/problem?id=2914

  求无源无汇又向图中的最小割。

  如果枚举源点和汇点然后用最大流求最小割,复杂度O( n^4 )的样子,肯定会超时。

  解决此类问题有一个Stoer Wagner算法,其思想类似于最小生成树的prim算法。

  推荐两篇文章:<文章一>   <文章二> 

  下面是模板:

/*    Stoer_Wagner  O(n^3)  (POJ 2914)
   求无向图的最小割,把图分为两个子图的最小花费
   邻接矩阵建图,w[][]点从0开始
   算法流程:
     1.min=MAXINT,固定一个顶点P
     2.从点P用“类似”prim的s算法扩展出“最大生成树”,记录最后扩展的顶点和最后扩展的边
     3.计算最后扩展到的顶点的切割值(即与此顶点相连的所有边权和),若比min小更新min
     4.合并最后扩展的那条边的两个端点为一个顶点(当然他们的边也要合并,这个好理解吧?)
     5.转到2,合并N-1次后结束
     6.min即为所求,输出min
   prim本身复杂度是O(n^2),合并n-1次,算法复杂度即为O(n^3)
   如果在prim中加堆优化,复杂度会降为O((n^2)logn)            */

int w[N][N];
int v[N], dis[N];
bool vis[N];
int n,m;

int Stoer_Wagner(int n){
    int i, j, res = INF;
    for(i = 0; i < n; i ++)
        v[i] = i;
    while(n > 1){
        int k = 1, pre = 0;
        for(i = 1; i < n; i ++){
            dis[v[i]] = w[v[0]][v[i]];
            if(dis[v[i]] > dis[v[k]])
                k = i;
        }
        memset(vis, 0, sizeof(vis));
        vis[v[0]] = true;
        for(i = 1; i < n; i ++){
            if(i == n-1){
                res = min(res, dis[v[k]]);
                for(j = 0; j < n; j ++){
                    w[v[pre]][v[j]] += w[v[j]][v[k]];
                    w[v[j]][v[pre]] += w[v[j]][v[k]];
                }
                v[k] = v[-- n];
            }
            vis[v[k]] = true;
            pre = k;
            k = -1;
            for(j = 1; j < n; j ++)
                if(!vis[v[j]]){
                    dis[v[j]] += w[v[pre]][v[j]];
                    if(k == -1 || dis[v[k]] < dis[v[j]])
                        k = j;
                }
        }
    }
    return res;
}

 

posted @ 2013-05-21 11:23  zhsl  阅读(589)  评论(0编辑  收藏  举报