前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UOJ#179. 线性规划(线性规划)

UOJ#179. 线性规划(线性规划)

作者头像
attack
发布2018-07-27 15:21:13
5210
发布2018-07-27 15:21:13
举报

这是一道模板题。

(这个题现在标程挂了。。哪位哥哥愿意提供一下靠谱的标程呀?)

本题中你需要求解一个标准型线性规划:

有 nn 个实数变量 x1,x2,…,xnx1,x2,…,xn 和 mm 条约束,其中第 ii 条约束形如 ∑nj=1aijxj≤bi∑j=1naijxj≤bi。

此外这 nn 个变量需要满足非负性限制,即 xj≥0xj≥0。

在满足上述所有条件的情况下,你需要指定每个变量 xjxj 的取值,使得目标函数 F=∑nj=1cjxjF=∑j=1ncjxj 的值最大。

输入格式

第一行三个正整数 n,m,tn,m,t。其中 t∈{0,1}t∈{0,1}。

第二行有 nn 个整数 c1,c2,⋯,cnc1,c2,⋯,cn,整数间均用一个空格分隔。

接下来 mm 行,每行代表一条约束,其中第 ii 行有 n+1n+1 个整数 ai1,ai2,⋯,ain,biai1,ai2,⋯,ain,bi,整数间均用一个空格分隔。

输出格式

如果不存在满足所有约束的解,仅输出一行 "Infeasible"。

如果对于任意的 MM,都存在一组解使得目标函数的值大于 MM,仅输出一行"Unbounded"。

否则,第一行输出一个实数,表示目标函数的最大值 FF。当第一行与标准答案的相对误差或绝对误差不超过 10−610−6,你的答案被判为正确。

如果 t=1t=1,那么你还需要输出第二行,用空格隔开的 nn 个非负实数,表示此时 x1,x2,…,xnx1,x2,…,xn 的取值,如有多组方案请任意输出其中一个。

判断第二行是否合法时,我们首先检验 F−∑nj=1cjxjF−∑j=1ncjxj 是否为 00,再对于所有 ii,检验 min{0,bi−∑nj=1aijxj}min{0,bi−∑j=1naijxj} 是否为 00。检验时我们会将其中大于 00 的项和不大于 00 的项的绝对值分别相加得到 S+S+ 和 S−S−,如果 S+S+ 和 S−S− 的相对误差或绝对误差不超过 10−610−6,则判为正确。

如果 t=0t=0,或者出现 Infeasible 或 Unbounded 时,不需要输出第二行。

样例一

input
代码语言:javascript
复制
2 2 1
1 1
2 1 6
-1 2 3
output
代码语言:javascript
复制
4.2
1.8 2.4 
explanation

两条约束分别为 2x1+x2≤6,−x1+2x2≤32x1+x2≤6,−x1+2x2≤3。

当 x1=1.8,x2=2.4x1=1.8,x2=2.4 时目标函数 x1+x2x1+x2 取到最大值 4.24.2。

样例二

input
代码语言:javascript
复制
2 2 1
1 -1
1 1 4
-1 -2 -2
output
代码语言:javascript
复制
4.0
4.0 0.0
explanation

注意 xj≥0xj≥0 的限制。

样例三

input
代码语言:javascript
复制
3 3 1
0 0 1
-2 1 0 -4
1 1 0 4
1 -2 0 -4
output
代码语言:javascript
复制
Infeasible

样例四

input
代码语言:javascript
复制
2 1 1
0 1
1 0 1
output
代码语言:javascript
复制
Unbounded

限制与约定

对于所有数据,1≤n,m≤201≤n,m≤20,0≤|aij|,|bi|,|cj|≤1000≤|aij|,|bi|,|cj|≤100,t∈{0,1}t∈{0,1}。

本题包含 4 个子任务,每个 25 分。

子任务 1,3 满足 bi≥0bi≥0。

子任务 2,4 没有特殊限制。

子任务 1,2 中 t=0t=0。

子任务 3,4 中 t=1t=1。

时间限制:1s1s

空间限制:256MB256MB

下载

样例数据下载

线性规划貌似在必修五有啊qwq不过还没学到估计也不会讲单纯形算法吧

感觉线性规划是差分约束的升级版??

如果想学的话建议看2016年队爷的论文《浅谈线性规划在信息学竞赛中的应用》

不过为啥A不了啊

代码语言:javascript
复制
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN = 51, INF = 1e9 + 10;
const double eps = 1e-8;
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, opt;
int id[MAXN];
double ans[MAXN], a[MAXN][MAXN];
void Pivot(int l, int e) {
    swap(id[N + l], id[e]);
    double t = a[l][e]; a[l][e] = 1;
    for(int i = 0; i <= N; i++) a[l][i] /= t;//交换基变量与非基变量 
    for(int i = 0; i <= M; i++) {
        if(i != l && abs(a[i][e]) > eps) {
            t = a[i][e]; a[i][e] = 0;//t表示系数 
            for(int j = 0; j <= N; j++)
                a[i][j] -= a[l][j] * t;//消去需要消去的非基变量 
        }
    }//带入的过程就是消去非基变量 
}
bool init() {
    //寻找初始化解,若bi < 0,找到一个ai < 0,转换它们,不断重复直到所有的bi都 > 0
    //此时x1 = 0, x2 = 0···就是一组解 
    while(1) {
        int l = 0, e = 0;
        for(int i = 1; i <= M; i++) if(a[i][0] < -eps && (!l || (rand() & 1))) l = i;
        if(!l) break;
        for(int i = 1; i <= N; i++) if(a[l][i] < -eps && (!e || (rand() & 1))) e = i;
        if(!e) {puts("Infeasible"); return 0;}
        //这里所有的Xi都是正的,而bi是负的,这与松弛型相矛盾 
        Pivot(l, e);
    }
    return 1;
}
bool simplex() {
    while(1) {
        int l = 0, e = 0; double mn = INF;
        for(int i = 1; i <= N; i++)
            if(a[0][i] > eps) 
                {e = i; 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 0;}
        Pivot(l, e);
    }
    return 1;
}
int main() {
    srand(19260817);
    N = read(); M = read(); opt = read();
    for(int i = 1; i <= N; i++) a[0][i] = read();//最大化C1X1 + C2X2··· 
    for(int i = 1; i <= M; i++) {
        for(int j = 1; j <= N; j++)
            a[i][j] = read();
        a[i][0] = read();// <= b 
    }
    for(int i = 1; i <= N; i++) id[i] =  i;
    if(init() && simplex()) {
        printf("%.8lf\n", -a[0][0]);
        if(opt) {
            for(int i = 1; i <= M; i++) ans[id[i + N]] = a[i][0];//tag
            for(int i = 1; i <= N; i++) printf("%.8lf ", ans[i]);
        }
    }
    return 0;
}
/*
3 3 1
3 1 2
1 1 3 30
2 2 5 24
4 1 2 36
*/
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 输入格式
  • 输出格式
  • 样例一
    • input
      • output
        • explanation
        • 样例二
          • input
            • output
              • explanation
              • 样例三
                • input
                  • output
                  • 样例四
                    • input
                      • output
                      • 限制与约定
                      • 下载
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档