zoukankan      html  css  js  c++  java
  • 线性规划(单纯形法)知识整理

    前言:内容有点多,自己写是不可能的


      这里挂两篇博客,复习的时候可以看看

        fjzzq’s blog 

        hrwhisper’s blog

      该算法的时间复杂度很迷,精度也很奇怪,$uoj$的题用$eps=1e-13$就炸了,用$1e-11$较好

      这里挂两个模板,对应不同的标准型,需要的时候可以选一个用,有时可以避免求基本解

      但注意若$b_i < 0$,无论哪个板都要先初始化求基本解

    模板:

      $Case 1$: 最大化          $sum_{j=1}^nc_jx_j$

          满足$m$条约束        $sum_{j=1}^na_{ij}x_j leqslant b_i$

          同时$n$个变量需要满足     $x_j geqslant 0$

       代码:(uoj179)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 50;
    const double eps = 1e-11;
    
    int n, m, typ, id[maxn], b[maxn];
    double a[maxn][maxn];
    
    void pivot(int x, int y)
    {
        swap(id[x+n], id[y]);
        double t = -a[x][y];
        a[x][y] = -1;
        for(int i = 0; i <= n; ++i)
            a[x][i] /= t;
        for(int i = 0; i <= m; ++i)
            if(a[i][y] && x != i)
            {
                t = a[i][y];
                a[i][y] = 0;
                for(int j = 0; j <= n; ++j)
                    a[i][j] += a[x][j] * t;
            }
    }
    
    void init()
    {
        for(int i = 1; i <= n; ++i)
            id[i] = i;
        int p, q;
        double t, w;    
        while(1)
        {
            p = q = 0;
            w = - eps;
            for(int i = 1; i <= m; ++i)
                if(a[i][0] < w)
                {
                    w = a[i][0];
                    p = i;
                }
            if(!p)    return;
            for(int i = 1; i <= n; ++i)
                if(a[p][i] > eps)
                {
                    q = i;
                    break;
                }
            if(!q)
            {
                printf("Infeasible");
                exit(0);
            }
            pivot(p, q);
        }
    }
    
    void simplex()
    {
        int p, q;
        double w;
        while(1)
        {
            p = q = 0;
            w = eps;
            for(int i = 1; i <= n; ++i)
                if(a[0][i] > w)
                {
                    p = i;
                    w = a[0][i];
                }
            if(!p)    return;
            w = 1e20;
            for(int i = 1; i <= m; ++i)
                if(a[i][p] < - eps && - a[i][0] / a[i][p] < w)
                {
                    w = - a[i][0] / a[i][p];
                    q = i;
                }
            if(!q)
            {
                printf("Unbounded");
                exit(0);
            }
            pivot(q, p);
        }
    }
    
    int main()
    {
        scanf("%d%d%d", &n, &m, &typ);
        for(int i = 1; i <= n; ++i)
            scanf("%lf", &a[0][i]);
        for(int i = 1; i <= m; ++i)
        {
            for(int j = 1; j <= n; ++j)
            {
                scanf("%lf", &a[i][j]);
                a[i][j] *= -1;
            }
            scanf("%lf", &a[i][0]);
        }
        init();
        simplex();
        printf("%.10f
    ", a[0][0]);
        if(!typ)    return 0;
        for(int i = n + 1; i <= n + m; ++i)
            b[id[i]] = i - n;
        for(int i = 1; i <= n; ++i)
            printf("%.10f ", b[i]? a[b[i]][0]: 0);
        return 0;
    }
    View Code 

      PS:只有97分

      

       $Case 2$: 最小化          $sum_{j=1}^nc_jx_j$

          满足$m$条约束        $sum_{j=1}^na_{ij}x_j geqslant b_i$

          同时$n$个变量需要满足     $x_j geqslant 0$

       代码:(bzoj3265志愿者招募加强版)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxm = 10005, maxn = 1005;
    const double eps = 1e-11;
    
    int n, m, id[maxm];
    double a[maxm][maxn];
    
    void pivot(int x, int y)
    {
        double w = -a[x][y];
        a[x][y] = -1;
        for(int i = 0; i <= n; ++i)
            a[x][i] /= w;
        for(int i = 0; i <= m; ++i)
            if(a[i][y] && x != i)
            {
                w = a[i][y];
                a[i][y] = 0;
                for(int j = 0; j <= n; ++j)
                    a[i][j] += w * a[x][j];
            }
    }
    
    void simplex()
    {
        int p, q;
        double w;
        while(1)
        {
            p = q = 0;
            w = eps;
            for(int i = 1; i <= n; ++i)
                if(a[0][i] > w)
                {
                    w = a[0][i];
                    p = i;
                    break;
                }
            if(!p)    return ;
            w = 1e18;
            for(int i = 1; i <= m; ++i)
                if(a[i][p] < -eps && - a[i][0] / a[i][p] < w)
                {
                    w = - a[i][0] / a[i][p];
                    q = i;
                }
            pivot(q, p);
        }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        int l, r, num;    
        for(int i = 1; i <= n; ++i)
            scanf("%lf", &a[0][i]);
        for(int i = 1; i <= m; ++i)
        {
            scanf("%d", &num);
            for(int j = 1; j <= num; ++j)
            {
                scanf("%d%d", &l, &r);
                for(int k = l; k <= r; ++k)
                    a[i][k] = -1;
            }
            scanf("%lf", &a[i][0]);
        }
        simplex();
        printf("%.0f", a[0][0]);
        return 0;
    }
    View Code

       PS:这道题一开始写的$Case 1$,当然需要先求基本解,于是就T飞了

      

  • 相关阅读:
    统计学_筛选试验
    ROC、PR 曲线/准确率、覆盖率(召回)、命中率、Specificity(负例的覆盖率)、F1 score
    阳/阴性预测值Positive/negative Predictive Value(推荐AA)
    统计学_样本量估计_python代码实现
    统计学_效应量Effect Size
    统计学_二型错误和功效(Type II Errors and Test Power)
    统计学的P值解释和误区
    【线性代数的几何意义】向量的基本几何意义
    【线性代数的几何意义】什么是线性代数
    【Eclipse】如何在Eclipse中使用命令行?
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/12220814.html
Copyright © 2011-2022 走看看