[单纯形法与线性规划]【学习笔记】

很早以前学过理论,3个月前又学了一遍写了一点笔记,现在觉得以(已)前(经)写(完)的(全)太(忘)丑(记)于是重写一遍

参考资料:

1.算法导论

2.2016国家集训队论文


 

标准型

Maximizej=1ncjxj

Satisfyconstraint:

j=1naijxjbi, i=1,2,...,m

xj0, j=1,2,...,n

 

n个变量,m+n个约束

构造mn的矩阵Am维向量bn维向量c

 

MaximizecTx

Satisfyconstraint:

Axb

x0

 

转化为标准型:

 

 

松弛型

松弛变量xn+i

j=1naijxjbi  xn+i=bij=1naijxj, xn+i0

等式左侧为基本变量,右侧为非基本变量

 


 

 

单纯型算法

每个约束定义了n维空间中的一个半空间(超平面),交集形成的可行域是一个凸区域称为单纯型

目标函数是一个超平面,最优解在凸区域定点处取得

 

基本解:非基本变量值为0,基本变量为右侧的常数

基本可行解:所有bi0

通过不断的转轴操作,在n维凸区域的顶点上不断移动(转轴),使得基本解的目标值不断变大,最终达到最优解

 

转轴:

选取一个非基本变量xe为替入变量,基本变量xl为替出变量,将其互换

为了防止循环,根据Bland规则,选择下标最小的变量

 

初始化:

算法导论上有一个辅助线性规划的做法

但我发现好多人都用了随机初始化的黑科技

在所有bi<0的约束中随机选一个作为xl,再随机选一个ale<0的作为xe,然后Pivot(l,e)bi就变正了...

 



代码实现:

直接用一个a[][]来保存目标函数和约束

Pivot里的各种操作推导一下很清楚,用了两个trick避免了一些判断

id用来保存基本变量和非基本变量集合

 

针对全幺模矩阵可以进行提取非零系数的优化

UOJ#179. 线性规划

复制代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=25;
const double eps=1e-8,INF=1e15;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int n,m,type;
double a[N][N],ans[N];
int id[N<<1];
int q[N];
void Pivot(int l,int e){
    swap(id[n+l],id[e]);
    double t=a[l][e]; a[l][e]=1;
    for(int j=0;j<=n;j++) a[l][j]/=t;
    for(int i=0;i<=m;i++) if(i!=l && abs(a[i][e])>eps){
        t=a[i][e]; a[i][e]=0;
        for(int j=0;j<=n;j++) a[i][j]-=a[l][j]*t;
    }
}
bool init(){
    while(true){
        int e=0,l=0;
        for(int i=1;i<=m;i++) if(a[i][0]<-eps && (!l||(rand()&1))) l=i;
        if(!l) break;
        for(int j=1;j<=n;j++) if(a[l][j]<-eps && (!e||(rand()&1))) e=j;
        if(!e) {puts("Infeasible");return false;}
        Pivot(l,e);
    }
    return true;
}
bool simplex(){
    while(true){
        int l=0,e=0; double mn=INF;
        for(int j=1;j<=n;j++) 
            if(a[0][j]>eps) {e=j;break;}
        if(!e) break;
        for(int i=1;i<=m;i++) if(a[i][e]>eps && a[i][0]/a[i][e]<mn)
            mn=a[i][0]/a[i][e],l=i;
        if(!l) {puts("Unbounded");return false;}
        Pivot(l,e);
    }
    return true;
}
int main(){
    freopen("in","r",stdin);
    srand(317);
    n=read();m=read();type=read();
    for(int i=1;i<=n;i++) a[0][i]=read();
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++) a[i][j]=read();
        a[i][0]=read();
    }
    for(int i=1;i<=n;i++) id[i]=i;
    if(init() && simplex()){
        printf("%.8lf\n",-a[0][0]);
        if(type){
            for(int i=1;i<=m;i++) ans[id[n+i]]=a[i][0];
            for(int i=1;i<=n;i++) printf("%.8lf ",ans[i]);
        }
    }
}
View Code
复制代码

 


 

 

 

问题转化为单纯型:

最短路

最大流

最小费用最大流

多商品流(目前没写过)

 

对偶性:

Max cTx : Axb, x0 MinbTy : ATyc, t0

最大化与最小化互换,常数与目标函数互换,改变不等号,变量与约束对应

最大流与最小割

二分图最大权匹配与最小顶标和

最小顶标和:一个带权二分图,两个顶点的顶标之和不小于连接它们的边的边权,求最小顶标和

所有边权为1,就是最大匹配和最小点覆盖

 

duv表示u,v是否匹配

Max(u,v)Ecuvduv

Sat

vYduv1uX

uXduv1vY

du,v{0,1}

 

pu,pv为两类约束对偶之后的变量


MinuXpu+vYpv

Sat

pu+pvcuvuX,vY

pu,pv0

 

 

全幺模矩阵(totally unimodular matrix)

充分条件:

1.仅有1,0,1构成

2.每列至多两个非零数

3.行可分为两个集合:

一列包含两个同号非零数,两行不在同一个集合

一列包含两个异号非零数,两行在同一个集合

 

线性规划中A为全幺模矩阵,则单纯形法过程中所有系数1,0,1

可以去除系数为0的项进行优化!

任何最大流、最小费用最大流的线性规划都是全幺模矩阵

 

posted @   Candy?  阅读(6549)  评论(3编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示