zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    local http
    redis 存储时间区间的数据
    json 和 jsonp
    ssdb 常用命令行
    php 冒泡排序
    pdo 函数
    异步的消息队列
    php 全局变量$_SERVER
    php 技能树
    get_called_class/get_class方法
  • 原文地址:https://www.cnblogs.com/heisenberg-/p/6430777.html
Copyright © 2011-2022 走看看