超市问题

一.实验题目
有个超市要开业了(营业时间8-19点),据经验统计,每个客人来结账的时间服从随机分布,每个顾客需要服务的时间服从正态分布(均值为2分钟,方差为1分钟),超市平时的顾客较少(8-12点、14-17点),顾客来结账的平均人数为60人/小时,而高峰期(12-14,17-19点)平均人数为300人/小时,平常顾客等待时间超过3分钟则不满意,而高峰期等待5分钟则不满意,顾客总是排在队列长度最短的队列后面。

功能要求:
(1)假设现在超市有3个结账出口,试模拟一天超市出口排队情况,并统计顾客不满意率。
(2)如果要求顾客不满意率降到2%,至少应有多少出口?

二.问题分析
1.此程序的核心数据结构为队列,顾客的排队过程即为进队与出队过程。
2.一天中的时间分为两个时间段----闲时和忙时。闲时顾客平均每分钟进队1个,忙时顾客平均每分钟进队5个。由于每个顾客来结账的时间服从随机分布,这里就将各位顾客进队的时间定在各个时间点上,如忙时进队时间分别为:08:01:00、08:02:00、08:03:00、08:04:00……,忙时进队时间分别为:12:00:00、12:00:12、12:00:24、12:00:36……
3.每个顾客需要服务的时间服从正态分布,平均值2分钟(即120秒),方差1分钟(即60秒)。如果写纯数学函数求随机服务时间,经过测试发现可能产生负数。这里结合实际将每个顾客需要的服务时间限制在60-120秒内。
4.根据实际情况及题目要求,顾客总是排在最短的队后面,故在每次顾客进队之前都要将最短的那个队列选择出来。
5.营业时间是从8:00到19:00,程序里面以秒为单位做循环。8:00时对应时间i=0,12:00对应i=14400,14:00对应i=21600,17:00对应i=32400,19:00对应i=39600.在需要显示几点几分几秒的时候再将i转换成时间格式。

三.数据结构设计
1.逻辑结构:循环队列
2. 存储结构:数据文件---记事本文件
3. 基本操作列表
*进队与出队操作
*数据文件的数据读写

四. 抽象数据类型

typedef struct customer
{
       int number;//第几号顾客
       int EnQueueTime;//进队时间
}customer;
typedef struct Queue
{
       int rear,front;
       customer element[maxsize];
}Queue;

五.算法设计
此程序所需要的数据可直接由系统模拟产生,不需要输入数据,结果输出的数据量较大,故将结果保存在txt文档中。
有3个结账出口时的顾客不满意率
思路:将顾客的进队时间分散到各个时间点上,每个时间点只有一个顾客进队,而且这个顾客进队之前都要判断哪个队是最短的,然后进到最短的那个队中。出队的时候可同时有一个或者多个顾客出队,只要这个顾客的出队时间到了就可以出队。程序里面用timeflagA、timeflagB、timeflagC、servicetime[30]作为时间标记,时间标记是根据randomtime往后推的。当i等于时间标记时当前的顾客就可以出队了。19:00之前有顾客进队,19:00之后没有顾客进队,但仍然有顾客在排队,所以必须保证当i循环完后所有的顾客都已经出队。出队过程中判断顾客是否满意并记录不满意的顾客数,循环结束之后就可以知道总的不满意顾客数,就可以求出顾客的不满意率。
如果要求顾客不满意率降到2%,至少应有多少出口?
由实际情况可知当中只有一个队的时候不满意率为最高,队越多不满意率越低,当队达到某个数量时不满意率会降至0,所以要将不满意率降到2%只需将队的数目循环递增即可,当达到要求后终止。

#include"stdio.h"
#include"stdlib.h"
#include"math.h"
#include"time.h"
#define maxsize 300//设定每个队的最大长度为300,实际情况每个队不可能排300个人
#define mu 2.0 //平均两分钟
#define sigma 1.0 //方差为1
int unsat=0;//不满意顾客数
int total=0;//总顾客数
int randomtime=0;
FILE * fp;

typedef struct customer
{
       int number;//第几号顾客
       int EnQueueTime;//进队时间
}customer;
typedef struct Queue
{
       int rear,front;
       customer element[maxsize];
}Queue;
//-------------------------------------------------------------------------------
double randomX(void)
{
       int a;
       double r;
       a=rand()%32767;
       r=(a+0.00)/32767.00;
       return r;
}
int Random()
{
       int i,m;
       shang:
       {
              double r,sum=0.0;   
              for(i=1;i<=12;i++)
              sum=sum+randomX();
              r=(sum-6.00)*sigma+mu;
              m=(int)(r*60);//转化成整数秒
       }
       if(m<60||m>180)
              goto shang;//若产生的随机时间小于60秒或者大于180秒则重新产生
       return  m;
}                                                                                  //这段产生随机数的代码是网上找的
//-------------------------------------------------------------------------------
void converttime(int time)//转换时间
{//将循环中i对应的时间转换成为几点几分几秒
       int a,b,c;
       a=(time/3600+8)%24;//时
       b=(time%3600)/60;//分
       c=time%60;//秒
       if(a<10)//小时
       {
              printf("0%d:",a);
              fprintf(fp,"0%d:
",a);
       }
       else
       {
              printf("%d:",a);
              fprintf(fp,"%d:
",a);
       }
       if(b<10)//分钟
       {
              printf("0%d:",b);
              fprintf(fp,"0%d:
",b);
       }
       else
       {
              printf("%d:",b);
              fprintf(fp,"%d:
",b);
       }
       if(c<10)//秒
       {
              printf("0%d ",c);
              fprintf(fp,"0%d 
",c);
       }
       else
       {
              printf("%d ",c);
              fprintf(fp,"%d 
",c);
       }
}//-------------------------------------------------------------------------------
void initQueue(Queue *Q)//初始化队列
{
       Q->front=Q->rear=0;
}//-------------------------------------------------------------------------------
int length(Queue *Q)//求队列长度
{
       return (Q->rear+maxsize-Q->front)%maxsize;
}//-------------------------------------------------------------------------------
int EnQueue(Queue *Q,int num,int time)//进队
{
       if((Q->rear+1)%maxsize==Q->front)
              return 0;
       Q->element[Q->rear].number=num;
       Q->element[Q->rear].EnQueueTime=time;//存储进队时间
       Q->rear=(Q->rear+1)%maxsize;
       return 1;
}//-------------------------------------------------------------------------------
int DeQueue1(Queue *Q,int time,int order)//闲时对应的出队函数,order为队列的序号
{
       if(length(Q)==0)
              return 0;
       converttime(time);//转换时间
       printf("第%d号顾客出第%d队  这位顾客开始排队的时间是:",Q->element[Q->front].number,order);
       fprintf(fp,"第%d号顾客出第%d队
",Q->element[Q->front].number,order); 
       fprintf(fp," 这位顾客开始排队的时间是:
"); 
       converttime(Q->element[Q->front].EnQueueTime); 
       if(time-Q->element[Q->front].EnQueueTime>180)
       {
              unsat++;//如果排队的时间超过180秒则不满意数加1
              fprintf(fp," 不满意!
");
              printf(" 不满意!
");
       }
       else
       {          
              fprintf(fp," 满意!
");
              printf(" 满意!
");
       }
       Q->front=(Q->front+1)%maxsize;
       return 1;
}//-------------------------------------------------------------------------------
int DeQueue2(Queue *Q,int time,int order)////忙时对应的出队函数
{
       if(length(Q)==0)
              return 0;     
       converttime(time);//转换时间
       printf("第%d号顾客出第%d队  这位顾客开始排队的时间是:",Q->element[Q->front].number,order);
       fprintf(fp,"第%d号顾客出第%d队
",Q->element[Q->front].number,order);
       fprintf(fp," 这位顾客开始排队的时间是:
");
       converttime(Q->element[Q->front].EnQueueTime);
       if(time-Q->element[Q->front].EnQueueTime>300)
       {
              unsat++;//如果排队的时间超过300秒则不满意数加1    
              fprintf(fp," 不满意!
");
              printf(" 不满意!
");
       }
       else
       {
              fprintf(fp," 满意!
");
              printf(" 满意!
");
       }
       Q->front=(Q->front+1)%maxsize;//front后移
       return 1;
}//-------------------------------------------------------------------------------
int main()
{
       time_t start,end;  
       start = time(NULL);
       fp = fopen("三个出口时的排队情况.txt","a");//以追加方式写入
       fprintf(fp,"超市有三个出口时的排队情况
");
       int i=1;
       int timeflagA=Random();//时间标记
       int timeflagB=Random();
       int timeflagC=Random();
       Queue A,B,C;
       initQueue(&A);
       initQueue(&B);
       initQueue(&C);
       int customertime;//=60;
       while(i<=70000)//8:00-19:00之间的四个小时共39600秒,加5分钟300秒
       {
              if(i<=39600)//i=39600对应时间是19:00,之后没有顾客进队
              {
                     if(i<=14400||(i>21600&&i<=32400))//闲时
                            customertime=60;
                     else //if((i>14400&&i<=21600)||(i>32400&&i<=39600))//忙时
                            customertime=12;
                     if(i%customertime==0)//有人来排队,customertime为一个人来排队到另外一个人来排队之间的间隔时间
                     {           
                            if(length(&A)<=length(&B)&&length(&A)<=length(&C))
                            {
                                   total++;
                                   EnQueue(&A,total,i);//A队最短          
                            }
                            else if(length(&B)<=length(&A)&&length(&B)<=length(&C))
                            {
                                   total++;
                                   EnQueue(&B,total,i);//B队最短,total表示来的第几个顾客,i为进队时间  
                            }
                            else
                            {
                                   total++;
                                   EnQueue(&C,total,i);//C队最短
                            }
                     }
              }//if(i<=39600)
              if(i==timeflagA)
              {
                     if(i<=14400||(i>21600&&i<=32400))
                            DeQueue1(&A,i,1);   //i为出队时间
                     else
                            DeQueue2(&A,i,1);
                     randomtime=Random();//randomtime即为下一名顾客的服务时间
                     timeflagA=randomtime+timeflagA;      
              }
              if(i==timeflagB)
              {
                     if(i<=14400||(i>21600&&i<=32400))
                            DeQueue1(&B,i,2);
                     else
                            DeQueue2(&B,i,2);
                     randomtime=Random();
                     timeflagB=randomtime+timeflagB;              
              }
              if(i==timeflagC)
              {
                     if(i<=14400||(i>21600&&i<=32400))
                            DeQueue1(&C,i,3);
                     else
                            DeQueue2(&C,i,3);
                     randomtime=Random();
                     timeflagC=randomtime+timeflagC;                    
              }
              i++;
       }//while(i<=79900)
       printf("不满意的顾客数为:%d,总的顾客数为:%d
",unsat,total);
       printf("不满意率为:%4.2f%%
",((double)unsat/(double)total)*100);
       fprintf(fp,"总顾客数为%d,其中不满意的顾客数为:%d
",total,unsat);
       fprintf(fp,"不满意率为:%4.2f%%
",((double)unsat/(double)total)*100);   
       fprintf(fp,"循环结束后的时间为:
");//连续两个%输出一个%
       converttime(i);
       fclose(fp);

       end = time(NULL);  
       printf("
The program used %-.2f seconds.
",difftime(end,start));

       return 0;
}

#include"stdio.h"
#include"stdlib.h"
#include"math.h"
#include"time.h"
#define maxsize 1620//设定每个队的最大长度为1620
#define mu 2.0 //平均两分钟
#define sigma 1.0 //方差为1
int unsat=0;//不满意顾客数
int total=0;//总顾客数
int randomtime=0;
FILE * fp;
typedef struct customer
{
       int number;//第几号顾客
       int EnQueueTime;//进队时间
}customer;
typedef struct Queue
{
       int rear,front;
       customer element[maxsize];
}Queue;
//-------------------------------------------------------------------------------
double randomX(void)
{
       int a;
       double r;
       a=rand()%32767;
       r=(a+0.00)/32767.00;
       return r;
}
int Random()
{
       int i,m;
       shang:
       {
              double r,sum=0.0;   
              for(i=1;i<=12;i++)
              sum=sum+randomX();
              r=(sum-6.00)*sigma+mu;
              m=(int)(r*60);//转化成整数秒
       }
       if(m<60||m>180)
              goto shang;//若产生的随机时间小于60秒或者大于180秒则重新产生
       return m;
}                                                                                  //这段产生随机数的代码是网上找的
//-------------------------------------------------------------------------------
void converttime(int time)//转换时间
{//将循环中i对应的时间转换成为几点几分几秒
       int a,b,c;
       a=(time/3600+8)%24;//时
       b=(time%3600)/60;//分
       c=time%60;//秒
       if(a<10)//小时
       {
              printf("0%d:",a);
              fprintf(fp,"0%d:
",a);
       }
       else
       {
              printf("%d:",a);
              fprintf(fp,"%d:
",a);
       }
       if(b<10)//分钟
       {
              printf("0%d:",b);
              fprintf(fp,"0%d:
",b);
       }
       else
       {
              printf("%d:",b);
              fprintf(fp,"%d:
",b);
       }
       if(c<10)//秒
       {
              printf("0%d ",c);
              fprintf(fp,"0%d 
",c);
       }
       else
       {
              printf("%d ",c);
              fprintf(fp,"%d 
",c);
       }
}//-------------------------------------------------------------------------------
void initQueue(Queue *Q)//初始化队列
{
       Q->front=0;
       Q->rear=0;
}//-------------------------------------------------------------------------------
int length(Queue *Q)//求队列长度
{
       return (Q->rear+maxsize-Q->front)%maxsize;
}//-------------------------------------------------------------------------------
int EnQueue(Queue *Q,int num,int time)//进队
{
       if((Q->rear+1)%maxsize==Q->front)
              return 0;
       Q->element[Q->rear].number=num;
       Q->element[Q->rear].EnQueueTime=time;//存储进队时间
       Q->rear=(Q->rear+1)%maxsize;//rear后移
       return 1;
}//-------------------------------------------------------------------------------
int DeQueue1(Queue *Q,int time,int order)//闲时对应的出队函数,order为队列的序号
{
       if(length(Q)==0)
              return 0;
       converttime(time);//转换时间
       printf("第%d号顾客出第%d队  这位顾客开始排队的时间是:",Q->element[Q->front].number,order);
       fprintf(fp,"第%d号顾客出第%d队
",Q->element[Q->front].number,order); 
       fprintf(fp," 这位顾客开始排队的时间是:
"); 
       converttime(Q->element[Q->front].EnQueueTime); 
       if(time-Q->element[Q->front].EnQueueTime>180)
       {
              unsat++;//如果排队的时间超过180秒则不满意数加1
              fprintf(fp," 不满意!unsat=%d
",unsat);
              printf(" 不满意!
");
       }
       else
       {          
              fprintf(fp," 满意!
");
              printf(" 满意!
");
       }
       Q->front=(Q->front+1)%maxsize;
       return 1;
}//-------------------------------------------------------------------------------
int DeQueue2(Queue *Q,int time,int order)////忙时对应的出队函数
{
       if(length(Q)==0)
              return 0;     
       converttime(time);//转换时间
       printf("第%d号顾客出第%d队  这位顾客开始排队的时间是:",Q->element[Q->front].number,order);
       fprintf(fp,"第%d号顾客出第%d队
",Q->element[Q->front].number,order);
       fprintf(fp," 这位顾客开始排队的时间是:
");
       converttime(Q->element[Q->front].EnQueueTime);
       if(time-Q->element[Q->front].EnQueueTime>300)
       {
              unsat++;//如果排队的时间超过300秒则不满意数加1    
              fprintf(fp," 不满意!unsat=%d
",unsat);
              printf(" 不满意!
");
       }
       else
       {
              fprintf(fp," 满意!
");
              printf(" 满意!
");
       }
       Q->front=(Q->front+1)%maxsize;//front后移
       return 1;
}//-------------------------------------------------------------------------------
int main()
{
    time_t start,end;  
    start = time(NULL);  
    fp = fopen("超市出口问题第二问beta1.txt","a");//以追加方式写入
    int i,j,k=0,m=1,n=0;
    int customertime;
    int servicetime[50];//服务时间标记    
    Queue Q[50];
    while(1)
    {
        fprintf(fp,"有%d个出口时的排队情况
",m);
        unsat=0;
        total=0;
        i=1;
        for(j=0;j<m;j++)
        {
            initQueue(&Q[j]);
            servicetime[j]=Random();
        }
        while(i<=800000)//8:00-19:00之间的四个小时共39600秒,加5分钟300秒
        {
            if(i<=39600)//i=39600对应时间是19:00,之后没有顾客进队
            {   
                if(i<=14400||(i>21600&&i<=32400))//闲时
                    customertime=60;/////////////////////////////////////////////////////////////////////////////////////
                else //if((i>14400&&i<=21600)||(i>32400&&i<=39600))//忙时
                    customertime=12;/////////////////////////////////////////////////////////////////////////////////////
                if(i%customertime==0)//有人来排队,customertime为一个人来排队到另外一个人来排队之间的间隔时间
                {           
                    for(j=0;j<m;j++)
                    {
                        if(length(&Q[j])<length(&Q[n]))
                            n=j;
                    }
                    total++;
                    EnQueue(&Q[n],total,i);//A队最短
                }
            }//if(i<=39600)
            for(j=0;j<m;j++)
            {
                if(i==servicetime[j])
                {
                    if(i<=14400||(i>21600&&i<=32400))
                        DeQueue1(&Q[j],i,j+1);   //i为出队时间
                    else
                        DeQueue2(&Q[j],i,j+1);
                    randomtime=Random();//randomtime即为下一名顾客的服务时间
                    servicetime[j]=randomtime+servicetime[j];      
                }
            }
            i++;
        }//while(i<=79900)
        printf("不满意的顾客数为:%d,总的顾客数为:%d
",unsat,total);
        printf("不满意率为:%4.2f%%
",((double)unsat/(double)total)*100);
        fprintf(fp,"总顾客数为%d,其中不满意的顾客数为:%d
",total,unsat);
        fprintf(fp,"不满意率为:%4.2f%%
",((double)unsat/(double)total)*100); 
        fprintf(fp,"循环结束后的时间为:
");
        converttime(i);     
        if(((double)unsat/(double)total)<0.02)
        {
            fprintf(fp,"
当有%d个出口时,不满意率低于2%%  O(∩_∩)O~~
",m);
            break;
        }
        else 
        {
            fprintf(fp,"
当有%d个出口时,不满意率高于2%%
-----------------------------------------------------------------------------------------------
",m);
            m++;            
        }
    }//while(1) 
    fclose(fp);

    end = time(NULL);  
    printf("
The program used %-.2f seconds.
",difftime(end,start));
    return 0;
}
原文地址:https://www.cnblogs.com/umgsai/p/11673143.html