uoj#179. 线性规划

题目链接

uoj#179. 线性规划

题解

引入基向量\(x_{i + n}\),将约束\(\sum_{i = 1}^{m}a_{ij}x_j \leq b_i\) 写为 $x_{i + n} = b_i - \sum_{i = 1}^m a_{ij} x_j $
目标函数 $\sum_{i = 1}^n C_i x_i $ 当存在 $ r,c$ 满足 \(C_c>0,B_r > 0,a_{rc} > 0\) ,把\(x_c\)作为第\(r\)个限制的基向量,得到$x_c = B_r - \sum_{c \geq j}a_{rj}x_j - x_{r + n} $
带入目标函数,非基向量取\(0\),一定可使目标函数增大,同时把其他约束中的\(x_c\)替换。
当所有的\(B_r > 0\)时一定能得到零解,存在\(B_r < 0\),在限制中找到一个小于\(0\)\(a_rc\)\(x_c\)带换为基向量,可以使\(B_r >0\) $x_i > 0 $
建议去看集训队论文
不过,为什么过不了

代码

#include<bits/stdc++.h> 
using namespace std;
#define eps 1e-8
#define INF 1e9 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' ||c > '9'){ if(c == '-')f = - 1; c = getchar();} 
    while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
int n,m,type,id[57]; 
double a[27][27],ans[57]; 
void pivot(int r,int c) { // swap basic varivle and nonbasic variable  
    swap(id[r + n],id[c]); 
    double t = a[r][c];a[r][c] = 1; 
    for(int i = 0;i <= n;++ i) a[r][i] /= t; 
    for(int i = 0;i <= m;++ i) 
        if(fabs(a[i][c]) > eps && i != r) { 
            t = a[i][c];a[i][c] = 0 ; 
            for(int j = 0;j <= n;++ j) a[i][j] -= t * a[r][j]; 
        } 
} 
bool init() {   
    for(int r,c;;) { 
        r = c = 0; 
        for(int i = 1;i <= m;++ i) 
            if(a[i][0] < -eps && (!r || rand() & 1)) r = i; 
        if(!r) return 1; 
        for(int i = 1;i <= n;++ i) 
            if(a[r][i] < -eps && (!c || rand() & 1)) c = i; 
        if(!c) return puts("Infeasible") , 0; 
        pivot(r,c); 
    } 
} 
bool simplex() { 
    for(int r,c;;) { 
        r = c = 0; 
        for(int i = 1;i <= n;++ i)// C[c] > 0; 
        if(a[0][i] > eps) {c = i;break;} 
        if(!c)return 1; 
        double mn = INF; //找约束最紧的正系数a[r][c]
        for(int i = 1;i <= m;++ i) 
            if(a[i][c] > eps && a[i][0] / a[i][c] < mn) r = i,mn = a[i][0] / a[i][c]; 
        if(! r) return puts("Unbounded"),0; 
        pivot(r,c); 
    } 
} 
int main() { 
    srand(20020711); 
    n = read(),m = read(),type = read(); 
    for(int i = 1;i <= n;++ i) a[0][i] = read(); //C[i] 
    for(int i = 1;i <= m;++ i) { 
        for(int j = 1;j <= n;++ j) a[i][j] = read(); 
        a[i][0] = read(); //B[i] 
    } 
    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[i + n]] = a[i][0]; //成为基变量的xi取值即为bi,非基变量上的xi取0. 
            for(int i = 1;i <= n;++ i) printf("%.8lf ",ans[i]); 
        } 
    } 
    return 0; 
} 

转载于:https://www.cnblogs.com/sssy/p/9386185.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值