线性规划初探

看完《算法导论》肯定会写单纯形

因为单纯形不仅好写而且《算法导论》里讲的很清楚

附赠uoj179的模板一个

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<stdlib.h>
  7
  8 using namespace std;
  9 const double eps=1e-9;
 10 double a[50][50];
 11 int b[50],u[50],n,m,ty;
 12
 13 int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 17     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 18     return x*f;
 19 }
 20 int dcmp(double x)
 21 {
 22     if (fabs(x)<=eps) return 0;
 23     if (x>0) return 1; else return -1;
 24 }
 25
 26 void pivot(int x,int y)
 27 {
 28      swap(b[x],u[y]);
 29      double k=a[x][y]; a[x][y]=1;
 30      for (int i=0; i<=n; i++) a[x][i]/=k;
 31      for (int i=0; i<=m; i++)
 32        if (i!=x&&dcmp(a[i][y])!=0)
 33        {
 34           k=a[i][y]; a[i][y]=0;
 35           a[i][0]+=(i?-1:1)*k*a[x][0];
 36           for (int j=1; j<=n; j++)
 37             a[i][j]-=k*a[x][j];
 38        }
 39 }
 40 bool initial()
 41 {
 42      for (int i=1; i<=n; i++) u[i]=i;
 43      for (int i=1; i<=m; i++) b[i]=n+i;
 44      while (1)
 45      {
 46            int x=0,y=0;
 47            for (int i=1; i<=m; i++)
 48              if (dcmp(a[i][0])<0) x=i; //加break会TLE?
 49            if (!x) return 1;
 50            for (int i=1; i<=n; i++)
 51              if (dcmp(a[x][i])<0) y=i;//加break会TLE?
 52            if (!y) return 0;
 53            pivot(x,y);
 54      }
 55 }
 56
 57 int simplex()
 58 {
 59     if (!initial()) return 0;
 60     while (1)
 61     {
 62           int x=0,y=0;
 63           for (int i=1; i<=n; i++)
 64             if (dcmp(a[0][i])>0) {y=i; break;}
 65           if (!y) return 1;
 66           double mi=1e15;
 67           for (int i=1; i<=m; i++)
 68             if (dcmp(a[i][y])>0&&(!x||a[i][0]/a[i][y]<mi)) {mi=a[i][0]/a[i][y];x=i;}
 69           if (!x) return -1;
 70           pivot(x,y);
 71     }
 72 }
 73 int main()
 74 {
 75     n=read(); m=read(); ty=read();
 76     for (int i=1; i<=n; i++) a[0][i]=read();
 77     for (int i=1; i<=m; i++)
 78     {
 79         for (int j=1; j<=n; j++) a[i][j]=read();
 80         a[i][0]=read();
 81     }
 82     switch (simplex())
 83     {
 84            case 1:{
 85                 printf("%.8lf\n",a[0][0]);
 86                 if (ty)
 87                 {
 88                    for (int i=1; i<=n; i++) u[i]=0;
 89                    for (int i=1; i<=m; i++) if (b[i]<=n) u[b[i]]=i;
 90                    for (int i=1; i<=n; i++) printf("%.8lf ",u[i]?a[u[i]][0]:double(0));
 91                 }
 92                 break;
 93            }
 94            case 0:puts("Infeasible");break;
 95            case -1:puts("Unbounded");break;
 96     }
 97     system("pause");
 98     return 0;
 99 }
100     

我唯一不解的是时间复杂度问题,据说会被卡但实际上基本跑得飞起(下面会用实例证明)

还有模板的initialization上有一处我很不解就是为什么在48行和51行处的循环加break和不加break在时间会带来明显的差距……

(uoj上这两处加上break会TLE……)求神犇指教……

下面是实际应用,凡是最大流,费用流的问题大概都能用线性规划解决,而且会很快变裸题……

比如这个1061,很明显把每天的要求人数bi作为约束,每种志愿者雇佣数量做变量xi

也就是求最小化∑ci*xi i=1..m

并且x要满足约数条件 ∑aij*xi>=bi i=1..n, j=1..m, ai,j=(sj<=i<=ti)?1:0,且xj非负

但是这与标准线性规划刚好相反,标准应该是全是<=且最大化

当然如果你看过《算法导论》关于单纯形最优解证明的话,你就会知道在对偶线性规划下这很简单

对于标准型线性规划:最大化∑ci*xi i=1..n ∑aij*xi>=bi i=1..m, j=1..n,x非负

我们很容易转化成对偶情况:最小化∑bi*xi i=1..m, ∑aij*xi>=bi i=1..n, j=1..m,x非负

这两种线性规划最优值相等(不禁联想到最大流和最小割的关系)

于是我们直接上单纯形即可

但是也许有疑虑,n<=1000,m<=10000能过吗&……

然而答案是c++版本的单纯形跑了1212ms,而我以前pascal版本的费用流跑了1764ms,

所以单纯形还是非常非常厉害的,大胆的使用吧……

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<stdlib.h>
 6
 7 using namespace std;
 8 const double eps=1e-9;
 9 int b[11100],u[11100],n,m;
10 double a[10010][1010];
11
12 int dcmp(double x)
13 {
14     if (fabs(x)<=eps) return 0;
15     if (x>0) return 1; else return -1;
16 }
17
18 void pivot(int x,int y)
19 {
20      swap(b[x],u[y]);
21      double k=a[x][y];a[x][y]=1;
22      for (int i=0; i<=n; i++) a[x][i]/=k;
23      for (int i=0; i<=m; i++)
24          if (i!=x&&dcmp(a[i][y])!=0)
25          {
26             k=a[i][y]; a[i][y]=0;
27             a[i][0]+=(i?-1:1)*k*a[x][0];
28             for (int j=1; j<=n; j++) a[i][j]-=k*a[x][j];
29          }
30 }
31
32 void simplex()
33 {
34      for (int i=1; i<=n; i++) u[i]=i;
35      for (int i=1; i<=m; i++) b[i]=i+n;
36      while (1)
37      {
38            int x=0,y=0;
39            for (int i=1; i<=n; i++)
40              if (dcmp(a[0][i])>0) {y=i;break;}
41            if (!y) break;
42            double mi=1e20;
43            for (int i=1; i<=m; i++)
44              if (dcmp(a[i][y])>0&&(!x||mi>a[i][0]/a[i][y])) {x=i; mi=a[i][0]/a[i][y];}
45            if (!x) break;
46            pivot(x,y);
47      }
48 }
49
50 int main()
51 {
52     scanf("%d%d",&n,&m);
53     for (int i=1; i<=n; i++) scanf("%lf",&a[0][i]);
54     for (int i=1; i<=m; i++)
55     {
56         int s,t,c;
57         scanf("%d%d%d",&s,&t,&c);
58         for (int j=s; j<=t; j++) a[i][j]=1;
59         a[i][0]=c;
60     }
61     simplex();
62     printf("%d\n",(int)a[0][0]);
63     system("pause");
64     return 0;
65 }

1061

时间: 2024-10-02 23:20:32

线性规划初探的相关文章

进阶之初探nodeJS

一.前言 在"初探nodeJS"随笔中,我们对于node有了一个大致地了解,并在最后也通过一个示例,了解了如何快速地开启一个简单的服务器. 今儿,再次看了该篇随笔,发现该随笔理论知识稍多,适合初级入门node,固萌生一个想法--想在该篇随笔中,通过一步步编写一个稍大一点的node示例,让我们在整体上更加全面地了解node. so,该篇随笔是建立在"初探nodeJS"之上的,固取名为"进阶之初探nodeJS". 好了,侃了这多,那么我们即将实现一个

从273二手车的M站点初探js模块化编程

前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数据. 273这个M站点是产品推荐我看的.第一眼看这个产品时我就再想他们这个三次加载和翻页按钮的方式,那么小分页的pageIndex是怎么计算的.所以就顺便看了下源码. 提到看源码时用到了Chrome浏览器的格式化工具(还是朋友推荐我的,不过这个格式化按钮的确不明显,不会的话自行百度). 三次加载和分

[转载]HDFS初探之旅

转载自 http://www.cnblogs.com/xia520pi/archive/2012/05/28/2520813.html , 感谢虾皮工作室这一系列精彩的文章. Hadoop集群(第8期)_HDFS初探之旅 1.HDFS简介 HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上.它所具有的高容错.高可靠性.高可扩展性.高

MongoDB初探系列之二:认识MongoDB提供的一些常用工具

在初探一中,我们已经可以顺利的将MongoDB在我们自己的机器上跑起来了.但是在其bin目录下面还有一些我们不熟知的工具.接下来,将介绍一下各个小工具的用途以及初探一中MongoDB在data文件夹下创建的文件的用途. 1.bin目录下面的各种小工具简介及使用方式 bsondump.exe 用于将导出的BSON文件格式转换为JSON格式mongo.exe mongoDB的客户端 mongod.exe 用于启动mongoDB的Server mongodump.exe 用于从mongodb数据库中导

Asynchronous Pluggable Protocols 初探

Asynchronous Pluggable Protocols,异步可插入协议,允许开发者创建可插协议处理器,MIME过滤器,以及命名空间处理器工作在微软IE4.0浏览器以及更高版本或者URL moniker中.这涉及到Urlmon.dll动态链接库所公开(输出)的可插协议诸多功能,本文不进行深入的原理讲解,只对它其中之一的应用进行解析,那就是如何将一个应用程序注册为URL协议. 应用场景: tencent协议: 当我们打开"tencent://message/?uin=要链接的QQ号 &qu

重新认识HTML,CSS,Javascript 之node-webkit 初探

今天我们来系统的.全面的 了解一下前端的一些技术,将有助于我们写出 更优秀的 产品 出来. 什么是HTML? HTML 是用来描述网页的一种语言. HTML 包含一些根节点,子节点,文本节点,属性节点,组成, 它通过一系列预定义标签来描述网页结构,如: <title>This is title</title> ,这个表明该网页的标题是 This is title. 什么是CSS? CSS 指层叠样式表 (Cascading Style Sheets),它描述浏览器显示如何显示htm

java进阶06 线程初探

线程,程序和进程是经常容易混淆的概念. 程序:就是有序严谨的指令集 进程:是一个程序及其数据在处理机上顺序执行时所发生的活动 线程:程序中不同的执行路径,就是程序中多种处理或者方法. 线程有两种方法实现 一:继承Thread 覆盖run方法 package Thread; public class Thread1 { public static void main(String[] args){ MyThread1 thread1=new MyThread1(); thread1.setName

数据加密解密初探

在一次网络通信或者是进程通信中,如果传输数据采用明文的方式,那么很容易被第三方"窃听"到,安全性难以保障. 而所谓加密是让数据从明文变成密文,传输过程中是密文,传送过去之后对方接收到的也是密文.--可以理解为密文就是乱码,看不出内在的任何意义,通常也都是逐位对应的. 在接收方接收到密文之后只有把它还原为原来的样子才可以理解对方说的具体是什么,此过程就叫做解密. 所谓系统的安全要实现的目标应该包括:机密性-confidentiality,完整性-integrity 和可用性-availa

Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性,不得不说下Http协议.我们常常听到说,Http是一个无状态协议,同一个会话的连续两个请求互相不了解,他们由最新实例化的环境进行解析,除了应用本身可能已经存储在全局对象中的所有信息外,该环境不保存与会话有关的任何信息.之所以我们在使用ASP.NET WebForm开发中会感觉不到Http的无状态特