POJ 2914 Minimum Cut Stoer Wagner 算法 无向图最小割

 POJ 2914 题意:给定一个无向图 小于500节点,和边的权值,求最小的代价将图拆为两个联通分量。

Stoer Wagner算法:

(1)用类似prim算法的方法求“最大生成树”,但是它比较的权值为w(A,x)A为所有在树上的点,x不在树上。

(2)剩下最后一个节点等待加入树的时候,用W(A,xn)更新ans ,并且将最后一个节点和倒数第二个节点合并。

(3)运行N-1次“最大生成树”,就得到了答案

补充几点:(1)像这种数据规模比较小的题目,没必要用优先队列或者堆优化,反而会超时。。

              (2)这道题用流输入输出会超时。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int LL;
const int maxn=500,maxm=maxn*maxn/2;
int w[maxn][maxn],dist[maxn],m,n,point[maxn];
bool intree[maxn];
int po(int x)
{
 if(x==point[x])return x;
     else return point[x]=po(point[x]);
}
void combine(int a,int b)
{
 a=po(a);b=po(b);
 bool counted[maxn];memset(counted,0,sizeof(counted));
 for(int i=0;i<n;i++)
     {
      int np=po(i);
      if((np==a)||(np==b)||(counted[np]))continue;
      counted[np]=true;
      w[np][a]+=w[np][b];w[a][np]+=w[b][np];
    }
 point[b]=a;
}
int main()
{
 ios::sync_with_stdio(false);
 while(scanf("%d%d",&n,&m)!=EOF)
     {
      memset(w,0,sizeof(w));
      int a,b,c;
      for(int i=0;i<m;i++)
          {
           scanf("%d%d%d",&a,&b,&c);
         w[a][b]+=c;w[b][a]+=c;      
        }
     for(int i=0;i<n;i++)
         point[i]=i;
     int ans=1e+9;
     for(int ii=1;ii<n;ii++)
         {
          if(ans==0)break;
          memset(dist,0,sizeof(dist));memset(intree,0,sizeof(intree));
          int pre=po(0),sum=1;
          intree[pre]=true;
          while(sum<=(n-ii))
              {
               int maxk=-1;
               bool counted[maxn];memset(counted,0,sizeof(counted));
               for(int i=0;i<n;i++)
                   {
                    int np=po(i);
                    if((intree[np])||(counted[np]))continue;
                    counted[np]=true;
                    dist[np]+=w[pre][np];
                    if((maxk==-1)||(dist[np]>dist[maxk]))
                        {
                         maxk=np;
                    }
                }
             if(maxk==-1){ans=0;break;}
             intree[maxk]=true;
             if(sum==(n-ii))
                 {
                  combine(pre,maxk);
                  ans=min(ans,dist[maxk]);
                }
             pre=maxk;
             sum++;
            }
        }
     printf("%d
",ans);
    } 
 return 0;
}
原文地址:https://www.cnblogs.com/heisenberg-/p/6430777.html