1 问题重述
近年来,大学用电浪费比较严重,集中体现在学生上晚自习上,一种情况是去某个教室上自习的人比较少,但是教室内的灯却全部打开,第二种情况是晚上上自习的总人数比较少,但是开放的教室比较多,这要求我们提供一种最节约、最合理的管理方法。下面是某学校收集的部分数据:
表1 教室相关数据
管理人员只需要每天晚上开一部分教室供学生上自习,每天晚上从7:00---10:00开放(如果哪个教室被开放,则假设此教室的所有灯管全部打开)。
完成以下问题:
1.假如学校有8000名同学,每个同学是否上自习相互独立,上自习的可能性为0.7.要使需要上自习的同学满足程度不低于95%,开放的教室满座率不低于4/5,同时尽量不超过90%。问该安排哪些教室开放,能达到节约用电的目的.
2.假设这8000名同学分别住在10个宿舍区,现有的45个教室分为9个自习区,按顺序5 个教室为1个区,即1,2,3,4,5为第1区,…,41,42,43,44,45为第9区。这10个宿舍区到9个自习区的距离见表2。学生到各教室上自习的满意程度与到该教室的距离有关系,距离近则满意程度高,距离远则满意程度降低。假设学生从宿舍区到一个自习区的距离与到自习区任何教室的距离相同。请给出合理的满意程度的度量,并重新考虑如何安排教室,既达到节约用电目的,又能提高学生的满意程度。另外尽量安排开放同区的教室。
3.假设临近期末,上自习的人数突然增多,每个同学上自习的可能性增大为0.85,要使需要上自习的同学满足程度不低于99%,开放的教室满座率不低于 4/5,同时尽量不超过95%。这时可能出现教室不能满足需要,需要临时搭建几个教室。假设现有的45个教室仍按问题2中要求分为9个区。搭建的教室紧靠在某区,每个区只能搭建一个教室,搭建的教室与该区某教室的规格相同(所有参数相同),学生到该教室的距离与到该区任何教室的距离假设相同。问至少要搭建几个教室,并搭建在什么位置,既达到节约用电目的,又能提高学满意度。
表2 学生区(标号为A)到自习区(标号为B)的距离(单位:米)
所有数据仅供计算参考.并非完全真实.
2模型假设
(1)学校人数恒定不变
(2)教室灯管全部正常工作
(3)学生上仔细固定在同一个教室
(4)每人占据一个座位
(5)满意程度只与距离有关
3符号定义
N—学校总人数
Nij—第i个宿舍区到第j个自习区上自习的人数
Xij--第i个宿舍区到第j个自习区上自习的距离
T1—一般时期同学上自习的可能性
T2—期末时同学上自习的可能性
M1—一般时期同学上自习的满足程度
M2--期末时同学上自习的满足程度
Zmax1--一般时期同学上自习教室的满座率最大值
Zmin1--一般时期同学上自习教室的满座率最小值
Zmax2--期末时同学上自习教室的满座率最大值
Zmin2--期末时同学上自习教室的满座率最小值
P—上自习开的灯的总功率
Pn—第n个教室灯的总功率
Rn—第n个教室的座位数
Rmin--座位数最少的教室座位数
Rmaxj--第j个自习区座位数最多的教室
Sij--第i个宿舍区同学到第j个自习区上自习的满意程度
S—总满意程度
K—满意程度比例系数
Bj--第j个自习区座位数
4 模型建立
(1)在问题1的条件下建模
1问题要求达到节约用电的目的。当开放的教室中所有的灯管的功率之和最小时,我们认为是最节约的方案。
我们把问题归结为一个整数规划问题,目标就是使总功率最小。有的教室可能不会开放,为了解决这个问题,我们引入45个变元Yn:
=0,当第n个教室开放
Yn{ (n=1,2,3…45)
=1,当第n个教室不开放
45
目标函数为minP=min∑Pn*Yn
n=1
45
又由题意知: ∑Yn<=45
n=1
能满足上自习要求的同学人数是:
M1*T1*N
在计算每个教室容纳多少同学时,为了节约电能,上自习教室的满座率应取最大值,即没个教室的人数为:
Rn*Zmax1
因此满足:
45
M1*T1*N<=∑Rn*Zmax1*Yn
n=1
又不能有空余的教室,因此:
45
∑Rn*Zmax1*Yn- M1*T1*N〈Rmin*Zmax1
n=1
建立模型Ⅰ:45
目标函数为 minP=min∑Pn*Yn
n=1
约束条件:
45
∑Yn<=45
n=1
45
M1*T1*N<=∑Rn*Zmax1*Yn
n=1
45
∑Rn*Zmax1*Yn- M1*T1*N〈Rmin*Zmax1
n=1
(2)在问题2的条件下建模
问题2要求给出满意程度的度量。我们认为满意程度只与距离有关且与距离成反比例关系,即:
Sij=K/Xij
另外,我们只考虑开放同区的教室,即某个或某些自习区可能不开放。因为某区是否开放有两种情况,我们对其建立0-1型整数规划模型,为此引入9个变元:
=0,第j个自习区不开放
Yj{(j=1,2…9)
=1,第j个自习区开放
建立模型Ⅱ:
目标函数:
10 9
maxS= max∑ ∑(K/Xij)
i=1j=1
45
minP=min∑Pn*Yn
n=1
约束条件:
45
∑Yn<=45
n=1
45
M1*T1*N<=∑Rn*Zmax1*Yn
n=1
45
∑Rn*Zmax1*Yn- M1*T1*N〈Rmin*Zmax1
n=1
Bj*Yj* Zmax1>= M1*T1*N
(3)在问题3的条件下建模
问题3出现了新的状况,由于人数的增多,可能要搭建新的教室才能满足同学的需求,并且每区最多建一个。
我们假设现在每个区都建了一个规格为该区最大的教室。每区教室总功率为:
Pmaxj (j=1,2…9)
这样每个区的教室数目为6个。
我们只须如2建立模型,然后根据每个区的开放教室的数量来判断是否需要此新建的教室,若多余,就不需要建了。
建立模型Ⅲ:
目标函数:
10 9
maxS= max∑ ∑(K/Xij)
i=1j=1
45
minP=min∑Pn*Yn
n=1
约束条件:
45
∑Yn<=45
n=1
45
M2*T2*N<=∑Rn*Zmax2*Yn
n=1
45
∑Rn*Zmax2*Yn- M2*T2*N〈Rmin*Zmax2
n=1
(Rmaxj+Bj)*Yj* Zmax2>= M2*T2*N
5模型求解
1 对模型Ⅰ求解
我们选用能够对整数规划问题快速求解的数学软件Lindo来对上面的模型求解,得到结果:
开放的教室是:4,5,6,7,8,9,10,12,13,14,16,17,18,19,20,21,22,23,24,27,28,29,30,32,35,37,38,45
2 对模型Ⅱ求解
109
maxS= max∑ ∑(K/Xij)
i=1j=1
开放的的自习区是:B1,B2,B3,B4
3 对模型Ⅲ求解
新教室搭建在B2,B3,B5,B7区
6 模型的优缺点及改进
1优点
1) 方法直观,算法简单实用,可以通过软件进行整数规划求解,节省人力和时间
2) 整数规划得到的结果稳定,只要给出基本的约束条件就能得到理想的结果,而约束条件只随题目的基本情况而改变,便于修改
3) 易于推广,非常实用
2 缺点
1) 对Lindo软件过于依赖
2) 对满意程度的度量太过简单化,不太切合实际
3改进
对满意程度进行更加细致的量化,同时考虑到教室的满座率对同学上自习的满意程度的影响
7模型的扩展与推广
该模型并不依存于这个题目而是具有广泛的代表性。运筹学的题目到都可以用整数规划模型解决。该模型提供了一类题目的解法。它和运输模型有异曲同工的特点。
通过该题目我们不仅可以优化管理自习室,还可以将其运用到建立工厂的分布.产品的生产等模型。此模型有很大的实际用途。
为了学习编程,我硬是写了一遍。经过运行调试,已基本无大碍!#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std
/********************************************/
class student
{
public:
student(){ stestnum=""sname==""}
void setmessage()
{
cin>>stestnum>>sname
}
string stestnum//考号
string sname//姓名
}
student cstu[64]
/********************************************/
const int row=8, col=8 //座位行和列
/********************************************/
void arrange_seat(int seat[][col])
void cancel_seat(int seat[][col])
void find_student(int seat[][col])
void find_seat(int seat[][col])
void display_seats(int seat[][col])
/********************************************/
void main()
{
int choose, seat[row][col],i,j
for (i=0i<rowi++)
{
for (j=0j<colj++)
{
seat[i][j] = 0//0表示座位为空
}
}
do
{
cout<<"-------------------------------------------"<<endl
<<"----输入:1------安排座位给新考生"<<"---"<<endl
<<"---- 2------取消某人考场座位"<<"---"<<endl
<<"---- 3------根据座位查询考生信息"<<"---"<<endl
<<"---- 4------根据准考证查询考生座位"<<" ---"<<endl
<<"---- 5------输出考场座次表"<<" ---"<<endl
<<"---- 0------退出!"<<" ---"<<endl
<<"-------------------------------------------"<<endl
cin>>choose
if (1 == choose) arrange_seat(seat)
else if (2 == choose) cancel_seat(seat)
else if (3 == choose) find_student(seat)
else if (4 == choose) find_seat(seat)
else if (5 == choose) display_seats(seat)
else exit(1)
} while( choose )
}
/********************************************/
//选择1,为新来的考生安排座位,方法:用户输入准考证号和姓名,系统随机产生
//-------该考生座位的行号和列号,要求做到一个考生只有一个座位,而且在已有考生的位
//-------置上不能再安排新的考生;
void arrange_seat(int seat[][col])
{
time_t t
int newseat,r=0,c=0
srand((unsigned int)time(&t))
for ( r=0r<rowr++)
{
for ( c=0c<colc++)
{
if (seat[r][c] == 0)break//有空位子
if (r==row &&c==col)
{
cout<<"本教室考生已满!"<<endl
return
}
}
}
//---------------------------------//
do
{
newseat = rand()%64//产生座位号
r = newseat/8//行
c = newseat - r*8 //列
}while ( seat[r][c] != 0)//座位已经有人重先产生座位号
//---------------------------------//
seat[r][c]=newseat
cout<<"请输入准考证号和姓名:"
cstu[newseat].setmessage() //把信息存储到学生类中
for (int i=0i<64i++)
{
if ( i != newseat) //相同准考证号不能重复申请位子
{
if ( cstu[newseat].stestnum == cstu[i].stestnum )
{
cout<<"对不起!该准考证号已申请过座位,请您核对后再输入:"
cstu[newseat].setmessage() //
i--
}
}
}
cout<<" *** 作成功!"<<endl
}
/********************************************/
//选择2,取消某人考场座位(假设取消后的座位别人能坐)
void cancel_seat(int seat[][col])
{
string name
int i,r,c
cout<<"输入要取消的考生姓名:"
cin>>name
for (i=0i<64i++)
{
if (cstu[i].sname == name)
{
r = i/8//行
c = i - r*8 //列
seat[r][c]=0//赋值为0代表此座位无人
cstu[i].stestnum = ""//清空存储信息
cstu[i].sname = ""
cout<<" *** 作成功!"<<endl
return
}
}
cout<<"该考场没有此人!"<<endl
cout<<endl
}
/********************************************/
//选择3,要求输入座位的行号和列号,然后显示该座位学生的信息;
void find_student(int seat[][col])
{
int r,c
cout<<"请输入行号row和列号col:"
cin>>r>>c
r = r-1
c = c-1
if ( cstu[r*8+c].stestnum =="" || cstu[r*8+c].sname == "")
{
cout<<"该座位目前为空."<<endl
}
else
{
cout<<"准考证:"<<cstu[r*8+c].stestnum<<", 姓名:"<<cstu[r*8+c].sname<<endl
}
cout<<endl
}
/********************************************/
//选择4,要求输入某考生准考证号,然后显示该学生的座位;
void find_seat(int seat[][col])
{
int r,c
string textnum
cout<<"请输入准考证号:"
cin>>textnum
for ( r=0r<rowr++)
{
for (c=0c<colc++)
{
if (textnum == cstu[r*8+c].stestnum)
{
cout<<"查询结果: "<<"row:"<<r+1<<","<<"col:"<<c+1<<endl
return
}
}
}
cout<<"准考证错误!"<<endl
cout<<endl
}
/********************************************/
//选择5,显示考场座次表,要求再每个座位对应的行列上显示该考生的准考证号。
void display_seats(int seat[][col])
{
int r,c
cout<<"本考场座位占用情况如下(*代表无人,数字代表准考证号):"<<endl
for ( r=0r<rowr++)
{
for (c=0c<colc++)
{
if (seat[r][c] != 0) //不为0则有人
{
//输出的行左对齐,列宽10
cout.setf(ios::left)
cout<<setw(10)<<(cstu[r*8+c].stestnum)//有人输出准考证号
}
else
{
cout.setf(ios::left)
cout<<setw(10)<<"********"//无人输出*******
}
}
}
cout<<endl<<endl
}
/********************************************/
1、在excel表格的第一个单元格内输入“讲台”两个字。
2、选中包括第一个单元格在内的五个单元格(根据班级具体人数分布)。
3、点击工具栏中的“合并居中”按钮。
4、可以将“讲台”位置调整如下图样式,继续在F列的2、3、4行输入排数。
5、然后在A2、B2,D2、E2中输入第一排的学生姓名。
6、选择C列中C2开始到C8的单元格(根据实际排数确定需要选中多少格)。
7、然后点击合并居中并输入“过道”两个字。
8、继续将空格的姓名位置输入完整,将排数补齐即可完成班级座位表。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)