线性规划(单纯形法)知识整理

  内容有点多,自己写是不可能的,下面挂两篇博客,复习的时候可以看看

    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\n", 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飞了

  

猜你喜欢

转载自www.cnblogs.com/Joker-Yza/p/12220814.html