lingo集合里面如何定义一个已知集合的子集

lingo用户手册_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
lingo用户手册
上传于|0|0|文档简介
&&lingo手册
阅读已结束,如果下载本文需要使用5下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩3页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢(一)在Lingo中使用集合
时间: 00:02:16
&&&& 阅读:11
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&1.&&& 在Lingo中使用集合
4.1 集合的基本用法和lingo模型的基本要素
Lingo虽然使用方便,但是如果要解决几万个,几十万个变量的优化问题时,我们总不能一个一个地列出x1,x2,&,x1000来解决,而这样的问题在实际企业的应用中也是经常遇到的。好在Lingo中设计了集合语言来表示大规模变量的输入,只需一行文字就可以建立起含有大规模变量的目标函数和成千上万条约束。而Lingo的早期版本软件Lindo却不包含这样的功能。
现通过下例来对Lingo的集合、属性概念进行介绍。
例2 SAILCO公司需要决定决定下四个季度的帆船生产量。下四个季度的帆船需求量分别为40条,60条,75条,25条,这些需求必须按时满足。每个季度正常的生产能力是40条帆船,每条帆船的生产费用为400美元。如果加班生产,每条船的生产费用为450美元。每个季度末,每条船的库存费用为20美元。假定生产提前期为0,初始库存为10条船。如何安排生产可使总费用最小?
分析与解:用DEM、RP、OP、INV分别表示需求量,正常生产的产量,加班生产的产量,库存量。则DEM、RP、OP、INV对每个季度都应有一个对应的值,也就是说他们都应该是一个由4个元素组成的数组,其中DEM已知,而RP,OP,INV未知。现在我们可以写出该问题的模型:
此外还有各变量非负的约束。
记4个季度组成的集合,他们就是DEM、RP、OP、INV等变量的下标集合,对于,都有值与之对应。LINGO正是充分利用这种数组及其下标的关系,引入了&集合&与&属性&的概念。本例中我们把称之为集合,DEM、RP、OP、INV称为集合具有的属性(即定义在该集合上的属性)。下图表示了这种集合与属性的关系。
集合QUARTERS的元素
定义在集合QUARTERS上的属性
下面我们看看Lingo中具体如何定义集合及其属性。下面是例2的Lingo代码:
QUARTERS/1,2,3,4/:DEM,RP,OP,INV;
Min=@sum(QUARTERS:400*RP+450*OP+20*INV);
@for(QUARTERS(I):RP(I)&=40;);
@for(QUARTERS(I)|I#GT#1:
INV(I)=INV(I-1)+RP(I)+OP(I)-DEM(I););
INV(1)=10+RP(1)+OP(1)-DEM(1);
DEM=40,60,75,25;
我们总结一下上面代码的特点:
(1)、模型以&MODEL:&开始,以&END&结束。它们之间由语句组成,可以分成三步分。
(2)、集合定义部分以&SETS:&开始,以&ENDSETS&结束。中间定义了集合和相应属性。语句&QUARTERS/1,2,3,4/:DEM,RP,OP,INV;&定义了集合QUARTERS,以及该集合的属性DEM、RP、OP、INV,其结果正是上表里面的16个变量名。可以定义空集合,比如&Empty set/1,2,3,4/;&空集合的用法将在派生集中讲述。
(3)、数据输入部分以&DATA:&开始,以&ENDDATA&结束,语句&DEM=40,60,75,25;&给出了常量DEM的值,即DEM(1)=40,DEM(2)=60,DEM(3)=75,DEM(4)=25. 语句&DEM=40,60,75,25;&也可以写成语句&DEM=40 60 75 25;&即数据之间可以用逗号或空格分开。
(4)、其他部分,给出了目标函数和约束。其中目标函数(&min=&后面所接的表达式)是用求和函数
&@sum=(集合(下标):关于集合的属性的表达式)&
的方式定义的,这个函数的功能是对语句冒号&:&后面的表达式,按照&:&前面的集合指定的下标元素进行求和。本例中目标函数也可以写成
&(QUARTERS(i):400*RP(i)+450*OP(i)+20*INV(i))&
这里&@sum&相当于求和符号,而&QUARTERS(i)&相当于&&,而由于本例中已默认对所有的QUARTERS的元素求和,所以实例中可以将下标i省略。
约束是用循环函数&@for(集合(下标):关于集合的属性的约束关系式)&的方式定义的,意思是对于&:&前面的集合的每个元素(下标),冒号&:&后面的约束关系式都要成立。但对于这个约束,实际上I=1时要用到变量,但我们定义属性变量的时候是从I=1开始的,即是一个常数,为了区别I=1和I=2,3,4,我们要将I=1的约束单独列出来,而对I=2,3,4的约束我们对集合下标做了的约束,即用了&#GT#1&(这个限制条件与集合之间有一个竖线&|&分开,称为过滤条件),&I#GT#1&就表示,&#GT#&是lingo中的逻辑表达式。
小结一下lingo模型最基本的组成要素:
(1)&&&&&&&
集合段:以&SETS:&开始,以&ENDSETS&结束。作用在于定义必要的集合和属性。注意一个细节,我们可以定义QUARTERS/1,2,3,4/,若QUARTERS有1000个元素,我们也不必将其一一列出,而可以简写为QUARTERS/1..1000/.
(2)&&&&&&&
目标和约束段:这部分不像其他部分,没有段的开始和结束的标记。因此是除去其他段以外的所有语句。
(3)&&&&&&&
数据段:以&DATA:&开始,以&ENDDATA&结束,作用在于对集合的属性输入必要的常数数据,格式为:& 属性=常数列表;常数列表中的常数或以逗号&,&分开,或以空格分开& &.
(4)&&&&&&&
初始段:以&INIT:&开始,以&ENDINIT&结束。作用在于对集合的属性定义初值。因为求解算法是迭代算法,所以一个好的初值可以让程序更快解决。定义初值的格式为:
属性=常数列表;
(5)&&&&&&&
计算段:以&CALC:&开始,以&ENDCALC&结束,作用在于对一些原始数据进行计算处理,这种处理是在输入数据后,求解模型前进行的。例如,对上面的例子,如果我们希望可以得到全年的总需求和季度平均需求,可以增加这个段:
(QUARTERS:DEM);!总需求;
(QUARTERS);!平均需求;
要注意的是计算段中语句是按顺序执行的,故上面的两个语句不能调换。
&标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:/douzujun/p/6683396.html
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!1.编写程序,把一个n个元素的集合{1,2,3,...n}中的所有的m个元素的子集输出来 - ITeye问答
假设有5个元素的集点,取出3个元素的可能子集如下: {1 2 3}、{1 2 4 }、{1 2 5}、{1 3 4}、{1 3 5}、{1 4 5}、{2 3 4}、{2 3 5}、{2 4 5}、{3 4 5} 请教各位有设么好的办法么
问题补充:能不能解说下啊,尤其是这个粗体部分,还有为什么要用抽象类啊
&br /&&div class="quote_title"&chen_yongkai 写道&/div&&div class="quote_div"&
&br /&&pre name="code" class="java"&public abstract class Combination {
private int n,
* @return the count
public int getCount() {
public int length() {
protected abstract void action(int[] index);
public Combination(int n, int r) {
public void stop() {
public void execute() {
int i = 0,
int[] a = new int[n];
while (!stopped) {
if ((a[i] - i) &= (n - r)) {
if (i == (r - 1)) {
int[] index = new int[r];
for (j = 0; j & j++) {
index[j] = a[j];
action(index);
a[i] = a[i] + 1;
a[i] = a[i - 1] + 1;
if (i == 0) {
public static void main(String[] args) {
final int[] a = { 1, 2, 3, 4, 5 };
Combination c = new Combination(5, 3) {
protected void action(int[] index) {
System.out.print("{ ");
for (int i : index) {
System.out.print(a[i] + " ");
System.out.println("}");
c.execute();
}}&/pre&
&br /&自己理解吧&/div&
&br /&
问题补充:麻烦解释下红色部分就行了
&br /&&div class="quote_title"&chen_yongkai 写道&/div&&div class="quote_div"&
&br /&&pre name="code" class="java"&public abstract class Combination {
private int n,
* @return the count
public int getCount() {
public int length() {
protected abstract void action(int[] index);
public Combination(int n, int r) {
public void stop() {
public void execute() {
int i = 0,
int[] a = new int[n];
while (!stopped) {
if ((a[i] - i) &= (n - r)) {
if (i == (r - 1)) {
int[] index = new int[r];
for (j = 0; j & j++) {
index[j] = a[j];
action(index);
a[i] = a[i] + 1;
a[i] = a[i - 1] + 1;
if (i == 0) {
public static void main(String[] args) {
final int[] a = { 1, 2, 3, 4, 5 };
Combination c = new Combination(5, 3) {
protected void action(int[] index) {
System.out.print("{ ");
for (int i : index) {
System.out.print(a[i] + " ");
System.out.println("}");
c.execute();
}&/pre&
&br /&自己理解吧&/div&
&br /&
问题补充:麻烦解释下while里面的
而递归正好能回避直接用了m层的for循环代码上也简洁,思路也清晰
递归看情况用吧,它确实很神奇,当然用起来也不是很容易,需要思路很清楚
单从递归有时候能把代码单化很多
说说思路吧
我要拿到m个的数组,那么相当于
m个位数遍历能取的数据
for(int i=0;i&n.length-m+层数;i++){
&& reslut[层数]=array[i];
&& for(int j=i;i&n.length-m+层数;j++){
&&&&& reslut[层数]=array[j];
&&&&&& for(int k=j;k&n.length-m+层数;k++){
&&&&&&& ...
&&&&&&& .../*里面一共要遍历m层*/
&&&&&&& ...
&&&&&& }
&&& }
如果光是满足这个题目,我的代码的核心部分很简单:
public static void combination(int n, int r) {
int i = 0;
int[] a = new int[r];
while (true) {
if (a[i] & n) {
if (i == (r - 1)) {
System.out.println(Arrays.toString(a));
a[i] = a[i - 1] + 1;
if (i == 0) {
public static void main(String[] args) {
combination(5, 3);
本人还是喜欢没有递归调用的算法
public class Find
static int []
static int count=0;
static int[]
private static void init(int n,int m){
if(m&=n&&m&0){
int[] t=new int [n];
for(int i=0;i&n;i++){
res =new int[m];
//这里是核心算法,其他都是初始化的方法
private static void search(int m){
int order =res.length-m;
for(int i=i&=arr.length-m;i++){
if(order&0&&res[order-1]&=arr[i])
res[order]=arr[i];
search(m-1);
print(res);
public static void find(int n,int m){
init(n,m);
search(m);
private static void print(int[] mid)
System.out.print("{");
for(int i=0;i&mid.length-1;i++){
System.out.print(mid[i]+",");
System.out.print(mid[mid.length-1]+"}\r\n");
public static void main(String[] args)
find(5,3);
这个题有意思
感觉楼上的方法复杂了
做个标记,明天贴代码
public void execute() {
int i = 0,
int[] a = new int[n];
while (!stopped) {
if (a[i] & n) {// 还未选到最大的数,继续递增,否则回退
if (i == (r - 1)) {// 组合数选择完毕
int[] index = new int[r];
for (j = 0; j & j++) {
index[j] = a[j];
action(index);// 使用当前的组合数做相应的操作
// 构造组合数
a[i] = a[i - 1] + 1;// 递增
// 不能回退,遍历完毕
if (i == 0) {
// 回退递增,比如i=2时:{ 1 2 5 }--&{ 1 3 4 }
用抽象类是为了子类可以自定义action操作,可以复用。
你的需求就是简单的打印组合,其他的场合可以用于复杂的计算或者解决一些遍历算法。
代码说明:
首先stop标志用于停止组合演算,比如你只想打印以1开始的组合就可以这样写
public static void main(String[] args) {
final int[] a = { 1, 2, 3, 4, 5 };
Combination c = new Combination(5, 3) {
protected void action(int[] index) {
if (index[0] == 1) {
System.out.print("{ ");
for (int i : index) {
System.out.print(a[i] + " ");
System.out.println("}");
c.execute();
public abstract class Combination {
private int n,
* @return the count
public int getCount() {
public int length() {
protected abstract void action(int[] index);
public Combination(int n, int r) {
public void stop() {
public void execute() {
int i = 0,
int[] a = new int[n];
while (!stopped) {
if ((a[i] - i) &= (n - r)) {
if (i == (r - 1)) {
int[] index = new int[r];
for (j = 0; j & j++) {
index[j] = a[j];
action(index);
a[i] = a[i] + 1;
a[i] = a[i - 1] + 1;
if (i == 0) {
public static void main(String[] args) {
final int[] a = { 1, 2, 3, 4, 5 };
Combination c = new Combination(5, 3) {
protected void action(int[] index) {
System.out.print("{ ");
for (int i : index) {
System.out.print(a[i] + " ");
System.out.println("}");
c.execute();
}
自己理解吧
假设有个集合拥有m个元素,任意的从集合中取出n个元素,则这n个元素所形成的可能子集有那些?
假设有5个元素的集点,取出3个元素的可能子集如下:
{1 2 3}、{1 2 4 }、{1 2 5}、{1 3 4}、{1 3 5}、{1 4 5}、{2 3 4}、{2 3 5}、{2 4 5}、{3 4 5}
这些子集已经使用字典顺序排列,如此才可以观察出一些规则:
如果最右一个元素小于m,则如同码表一样的不断加1
如果右边一位已至最大值,则加1的位置往左移
每次加1的位置往左移后,必须重新调整右边的元素为递减顺序
所以关键点就在于哪一个位置必须进行加1的动作,到底是最右一个位置要加1?还是其它的位置?
在实际撰写程式时,可以使用一个变数positon来记录加1的位置,position的初值设定为n-1,因为我们要使用阵列,而最右边的索引值为最大的n-1,在position位置的值若小于m就不断加1,如果大于m了,position就减1,也就是往左移一个位置;由于位置左移后,右边的元素会经过调整,所以我们必须检查最右边的元素是否小于m,如果是,则position调整回n-1,如果不是,则positon维持不变。
code="java"]
public class NofM
&&& private int[]&&&
&&& public NofM(int n, int m)
&& {&&&&&&&
&&&&&&& this.m =&&&&&&&
&&&&&&& first =&&&&&&&
&&&&&&& position = n - 1;&&&&&&&&
&&&&&&& set = new int[n];&&&&&&&
&&&&&&& for(int i = 0; i & i++)&&&&&&&&&&&&
&&&&&&&&&&& set[i] = i + 1;&&&&
&&& public boolean hasNext() {&&&&&&&
&&&&&&& return set[0] & m - set.length + 1;&&&
&&& public int[] next()
&&& {&&&&&&&
&&&&&&& if(first) {&&&&&&&&&&&
&&&&&&&&&&& first =&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&& }&&&&&&&&&&&&&&&
&&&&&&& if(set[set.length-1] == m)&&&&&&&&&&&&
&&&&&&&&&&& position--;&&&&&&&&
&&&&&&& else&&&&&&&&&&&&
&&&&&&&&&&& position = set.length - 1;&&&&&&&&
&&&&&&& set[position]++;&&&&&&&& // 调整右边元素&&&&&&&&
&&&&&&& for(int i = position + 1; i & set. i++)&&&&&&&&&&&&
&&&&&&&&&&& set[i] = set[i-1] + 1;&&&&&&&&&&&&&&&
&&&&&&&&&&
&&& public static void main(String[] args) {&&&&&&&
&&&&&&& NofM nOfm = new NofM(4, 9);&&&&&&&&&&&&&&&
&&&&&&& while(nOfm.hasNext()) {&&&&&&&&&&&
&&&&&&&&&&& int[] set = nOfm.next();&&&&&&&&&&&
&&&&&&&&&&& for(int i = 0; i & set. i++) {&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& System.out.print(set[i]);&&&&&&&&&&&&&&
&&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&& System.out.println();&&&&&&&
&&&&&&& }&&&
原文地址:
已解决问题
未解决问题

我要回帖

更多关于 lingo定义矩阵 的文章

 

随机推荐