zoukankan      html  css  js  c++  java
  • 全局最小割 stoer-wagner与karger-stein算法

    stoer-wagner算法

    进行n轮操作,每轮操作确定一对点s,t被割开情况下的最小割,然后将s,t合并。s,t为操作中最后剩下的两个点。

    操作类似prim求最大生成树,每次将与当前集合相邻的距离最大的点合并到集合中,最后剩下s,t两点。

    代码来自wiki

    const int maxn = 550;
    const int inf = 1000000000;
    int n, r;
    int edge[maxn][maxn], dist[maxn];
    bool vis[maxn], bin[maxn];
    void init() {
        memset(edge, 0, sizeof(edge));
        memset(bin, false, sizeof(bin));
    }
    int contract( int &s, int &t ) {        // Find s,t
        memset(dist, 0, sizeof(dist));
        memset(vis, false, sizeof(vis));
        int i, j, k, mincut, maxc;
        for(i = 1; i <= n; i++) {
            k = -1;
            maxc = -1;
            for(j = 1; j <= n; j++)if(!bin[j] && !vis[j] && dist[j] > maxc) {
                    k = j;
                    maxc = dist[j];
                }
            if(k == -1)return mincut;
            s = t;
            t = k;
            mincut = maxc;
            vis[k] = true;
            for(j = 1; j <= n; j++)if(!bin[j] && !vis[j])
                    dist[j] += edge[k][j];
        }
        return mincut;
    }
    
    int Stoer_Wagner() {
        int mincut, i, j, s, t, ans;
        for(mincut = inf, i = 1; i < n; i++) {
            ans = contract( s, t );
            bin[t] = true;
            if(mincut > ans)mincut = ans;
            if(mincut == 0)return 0;
            for(j = 1; j <= n; j++)if(!bin[j])
                    edge[s][j] = (edge[j][s] += edge[j][t]);
        }
        return mincut;
    }

    --------------------------------------------------------------------------------------------------------

     对于特殊的所有边权值都为1的全局最小割,存在复杂度更低但常数较大的karger-stein算法

    考虑store-wagner的缩边的过程。如果随机取边,正确性会怎样呢?

    假设最小割为k,则边数 。选中最小割中任意一条边的概率

    将这条边缩去重复直到只剩两个点,每一步都不选中最小割中边的概率为

    这样我们重复n2logn次失败的概率,此处使用了e的定义式

    于是我们得到了在n^2mlogn时间复杂度下,1/n正确率的算法

    在进行这个过程时每当图的点数变为原图的1/√2时,记录当前状态后进行两次对该状态的求解

    这个做法的正确概率为

    时间复杂度为

    重复log2n次,我们就可以得到在n^2log^3n的复杂度下达到1./n正确性的算法

     在实际测试中的表现

          10次Karger-stein     stoer-wagner

     n=2000       40s       10s

     n=5000       340s      134s

    但是在这种情况下Karger-stein的正确率都大于1/2,有一定的优越性。

    另外,所有最小割在Karger-stein运行过程中未被找到的数量的期望是1/n,几乎可以找到所有合法的最小割。

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #define ULL unsigned long long 
    #define LDB long double
    using namespace std;
    
      ULL sed=233;
      int top,deg[5010],b[5010][5010],totdeg,n,m,succ[5010],prev[5010],faqcnt=0;
      map <int,int> mp;
      
      struct data{
          int x,y,k,num;
      }sta[5000*5000+1];
    
      ULL ran(){
          sed*=1280313;sed+=12413;sed^=123893;
          return(sed);
      }
    
      void restore(int tar){
          while (top>tar){
            data t=sta[top];top--;
            int x=t.x,y=t.y,i=t.k,num=t.num;
          if (t.k==-1){
              deg[x]+=num;deg[y]+=num;
            b[x][y]=b[y][x]=num;
            totdeg+=2*num;
            succ[prev[x]]=x;prev[succ[x]]=x;
          }else{
              deg[x]+=num;deg[y]-=num;
              b[y][i]=(b[i][y]-=num);
              b[x][i]=b[i][x]=num;
          }
        }
      }
    
      void contract(int x,int y){
        sta[++top]=(data){x,y,-1,b[x][y]};
        deg[x]-=b[x][y];deg[y]-=b[x][y];
        totdeg-=2*b[x][y];
        b[x][y]=b[y][x]=0;
        prev[succ[x]]=prev[x];succ[prev[x]]=succ[x];
          for (int i=0;i<=n;i=succ[i]) if (b[x][i]){
            sta[++top]=(data){x,y,i,b[x][i]};
            deg[x]-=b[x][i];deg[y]+=b[x][i];
            b[y][i]=(b[i][y]+=b[x][i]);
            b[x][i]=b[i][x]=0;
        }
      }
    
      void del(){
          int tar=ran()%totdeg+1,x,y;
          for (x=0;tar>deg[x];tar-=deg[x],x=succ[x]);
          for (y=0;tar>b[x][y];tar-=b[x][y],y=succ[y]);
          contract(x,y);
      }
    
      int slowsolve(int po){
        int ttop=top;
          for (int i=1;i<=po-2;i++) del();
        int ret=totdeg/2;
          restore(ttop);
          return(ret);
      }
    
      int fastsolve(int po){
        int ttop=top,ret=1e9;mp[po]++;
          if (po<=20){
            int ret=1e9;
            for (int i=1;i<=100;i++){
                ret=min(ret,slowsolve(po));
                restore(ttop);
          }
          return(ret);    
        }
        
        int tar=ceil(1+po/sqrt(2));
        for (int i=1;i<=po-tar;i++) del();
        ret=min(ret,fastsolve(tar));
        restore(ttop);
        
        for (int i=1;i<=po-tar;i++) del();
        ret=min(ret,fastsolve(tar));
        restore(ttop);
        return(ret);
      }
    
      int main(){
          scanf("%d%d",&n,&m);
          prev[n+1]=n;succ[0]=1;
          for (int i=1;i<=n;i++) prev[i]=i-1,succ[i]=i+1;
          for (int i=1;i<=m;i++){
            int t1,t2;
            scanf("%d%d",&t1,&t2);
          deg[t1]++;deg[t2]++;b[t1][t2]++;b[t2][t1]++;
          totdeg+=2;    
        }
        
        int ans=1e9;
        for (int i=1;i<=10;i++){
          int t=fastsolve(n);
          ans=min(ans,t);    
          printf("%d
    ",t);
        }
          
        printf("%d
    ",ans);
      }
  • 相关阅读:
    CSS改变插入光标颜色caret-color简介及其它变色方法(转)
    Javascript常见性能优化
    安装和使用Karma-Jasmine进行自动化测试
    宝塔 ftp 不能连接 列出时出错
    windows 开机总动运行bat文件
    PHP回调函数--call_user_func_array
    php 获取数组第一个key 第一个键值对 等等
    ssi的使用 开启 配置等
    go get请求 json字符串转为结构体
    php protected 类型如何获取
  • 原文地址:https://www.cnblogs.com/zhujiangning/p/8067609.html
Copyright © 2011-2022 走看看