您的位置:首页 > 其它

5-48 银行排队问题之单窗口“夹塞”版 (30分)

2016-04-30 08:20 381 查看
5-48 银行排队问题之单窗口“夹塞”版 (30分)

排队“夹塞”是引起大家强烈不满的行为,但是这种现象时常存在。在银行的单窗口排队问题中,假设银行只有1个窗口提供服务,所有顾客按到达时间排成一条长龙。当窗口空闲时,下一位顾客即去该窗口处理事务。此时如果已知第ii位顾客与排在后面的第jj位顾客是好朋友,并且愿意替朋友办理事务的话,那么第ii位顾客的事务处理时间就是自己的事务加朋友的事务所耗时间的总和。在这种情况下,顾客的等待时间就可能被影响。假设所有人到达银行时,若没有空窗口,都会请求排在最前面的朋友帮忙(包括正在窗口接受服务的朋友);当有不止一位朋友请求某位顾客帮忙时,该顾客会根据自己朋友请求的顺序来依次处理事务。试编写程序模拟这种现象,并计算顾客的平均等待时间。

输入格式:

输入的第一行是两个整数:1\le N \le 100001≤N≤10000,为顾客总数;0
\le M \le 1000≤M≤100,为彼此不相交的朋友圈子个数。若MM非0,则此后MM行,每行先给出正整数2\le
L \le 1002≤L≤100,代表该圈子里朋友的总数,随后给出该朋友圈里的LL位朋友的名字。名字由3个大写英文字母组成,名字间用1个空格分隔。最后NN行给出NN位顾客的姓名、到达时间TT和事务处理时间PP(以分钟为单位),之间用1个空格分隔。简单起见,这里假设顾客信息是按照到达时间先后顺序给出的(有并列时间的按照给出顺序排队),并且假设每个事务最多占用窗口服务60分钟(如果超过则按60分钟计算)。

输出格式:

按顾客接受服务的顺序输出顾客名字,每个名字占1行。最后一行输出所有顾客的平均等待时间,保留到小数点后1位。

输入样例:

6 2
3 ANN BOB JOE
2 JIM ZOE
JIM 0 20
BOB 0 15
ANN 0 30
AMY 0 2
ZOE 1 61
JOE 3 10

输出样例:

JIM
ZOE
BOB
ANN
JOE
AMY
75.2


时间限制:400ms
内存限制:64MB
代码长度限制:16kB
判题程序:系统默认
作者:DS课程组
单位:浙江大学


题目地址如下

https://pta.patest.cn/pta/test/15/exam/4/question/895

AC代码(选测试平台g++,我用vs2010写的,还未优化,):
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std ;

int n , m ;

struct cust
{
int come_no;
int int_name ;
int T ;
int P ;
};

int str2int(char name[])
{
return (name[0]-'A' + 1) * 27 * 27  +
(name[1]-'A' + 1)  * 27 +
(name[2]- 'A' + 1) ;
}

char* int2str(int num)
{
char* name2 = (char*)malloc(sizeof(char)*4);
int a = num / (27*27) ;
int b = num / 27 - a*27;
int c = num % 27 ;
name2[0] = a + 'A' - 1 ;
name2[1] = b + 'A' - 1 ;
name2[2] = c + 'A' - 1 ;
name2[3] = '\0' ;
return name2;
}

map<int , int> fri_no ;

vector<cust> vv;

int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
int i, L;
char name[4];
for(i=1;i<=m;i++)
{
scanf("%d",&L);
while(L--)
{
scanf("%s",name);
int int_name = str2int(name);
fri_no[int_name] = i ;
}
}
int first_time = 0 ;
cust ctmp ;
for(i=1;i<=n;i++)
{
scanf("%s %d %d", name , &ctmp.T,&ctmp.P) ;
if(ctmp.P > 60) //时间处理
ctmp.P = 60 ;
ctmp.int_name = str2int(name) ; // 字符串name转换成int型name
ctmp.come_no = i ;

if(i == 1 ) // 第一位顾客不用等待
{
first_time = ctmp.T ;
ctmp.T = 0 ;
}else{
ctmp.T -= first_time ;
}
vv.push_back(ctmp) ;
}
int out_count = 0; //完成服务的顾客数目
int pre_out_int_name ; // 上一个服务顾客的int_name
int now_time = 0 ; // 当前时刻
int total_wait_time = 0 ;//总共的等待时间
while(out_count < n)
{
if(out_count == 0)
{
cust now_cust = vv.at(0);
vv.erase(vv.begin());

pre_out_int_name = now_cust.int_name ;
total_wait_time =  0 ;
now_time = now_cust.T + now_cust.P ;
}else{
int tmp_fri_num = fri_no[pre_out_int_name] ; //朋友圈编号
int place = 0;
cust next_cust = vv.at(0);
for(int j = 0 ;j < (int)vv.size() ; j ++)
{
cust cust_tmp = vv.at(j) ;
int cust_tmp_fri_num = fri_no[cust_tmp.int_name];
if(cust_tmp.T <= now_time && cust_tmp_fri_num == tmp_fri_num && tmp_fri_num != 0)
{
next_cust = cust_tmp ;
place = j ;
break;
}
}

vv.erase(vv.begin() + place) ; //删除已经服务的顾客

if(next_cust.T > now_time) //如果 到达时间 大于 当前时间
{
now_time = next_cust.T + next_cust.P ;
total_wait_time += 0;//next_cust.T ; 这里不用等待
}else{
total_wait_time += (now_time - next_cust.T);
now_time += next_cust.P ;
}
pre_out_int_name = next_cust.int_name ;
}
out_count++;
printf("%s\n",int2str(pre_out_int_name)); //顺序打印名字
}
printf("%.1f\n",(1.0*total_wait_time)/n);
return 0 ;
}


思路: 此题是个模拟题,所以刚开始应该是纸上模拟下,看看自己能否把题目测试的例子给完成



(可以调用下 windows calc / linux bc命令,用计算机帮个忙)

接着开始编码了:
对于人名的字符串可以采用 转int型处理,这样方便,我写了两个函数
对于属于同一组的,采用map(没有的map值为0)
然后采用了while 来模拟时间

很遗憾,自己错了几次,也是发现问题的过程,充分发现自己有时候考虑有点不全
注意点:
1 第一个人 不用等待,等待时间大于当前时间,也不用等待
2 题目已经明确了输入,输出。。
3 就是个人思考问题了,题目不难,好像类似这种题的很多,有些还很难。
23分的:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std ;

int n , m ;

struct cust
{
int come_no;
int int_name ;
int T ;
int P ;
};

int str2int(char name[])
{
return (name[0]-'A' + 1) * 27 * 27  +
(name[1]-'A' + 1)  * 27 +
(name[2]- 'A' + 1) ;
}

char* int2str(int num)
{
char* name2 = (char*)malloc(sizeof(char)*4);
int a = num / (27*27) ;
int b = num / 27 - a*27;
int c = num % 27 ;
name2[0] = a + 'A' - 1 ;
name2[1] = b + 'A' - 1 ;
name2[2] = c + 'A' - 1 ;
name2[3] = '\0' ;
return name2;
}

map<int , int> fri_no ;

vector<cust> vv;

int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
int i, L;
char name[4];
for(i=1;i<=m;i++)
{
scanf("%d",&L);
while(L--)
{
scanf("%s",name);
int int_name = str2int(name);
fri_no[int_name] = i ;
}
}
cust ctmp ;
for(i=1;i<=n;i++)
{
scanf("%s %d %d", name , &ctmp.T,&ctmp.P) ;
if(ctmp.P > 60)
ctmp.P = 60 ;
ctmp.int_name = str2int(name) ;
ctmp.come_no = i ;
vv.push_back(ctmp) ;
}
int out_count = 0; //完成服务的顾客数目
int pre_out_int_name ; // 上一个服务顾客的int_name
int now_time = 0 ; // 当前时刻
int total_wait_time = 0 ;//总共的等待时间
while(out_count < n)
{
if(out_count == 0)
{
cust now_cust = vv.at(0);
vv.erase(vv.begin());

pre_out_int_name = now_cust.int_name ;
total_wait_time += now_cust.T ;
now_time = now_cust.T + now_cust.P ;
}else{
int tmp_fri_num = fri_no[pre_out_int_name] ;
int place = 0;
cust next_cust = vv.at(0);
for(int j = 0 ;j < (int)vv.size() ; j ++)
{
cust cust_tmp = vv.at(j) ;
if(cust_tmp.T < now_time &&  fri_no[cust_tmp.int_name] == tmp_fri_num)
{
next_cust = cust_tmp ;
place = j ;
break;
}
}

vv.erase(vv.begin() + place) ; //删除已经服务的顾客

if(next_cust.T > now_time)
{
now_time = next_cust.T + next_cust.P ;
total_wait_time += next_cust.T ;
}else{
total_wait_time += (now_time - next_cust.T);
now_time = now_time + next_cust.P ;
}
pre_out_int_name = next_cust.int_name ;
}
out_count++;
printf("%s\n",int2str(pre_out_int_name)); //顺序打印名字
}
printf("%.1f\n",1.0*total_wait_time/n);
return 0 ;
}
28分的
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std ;

int n , m ;

struct cust
{
int come_no;
int int_name ;
int T ;
int P ;
};

int str2int(char name[])
{
return (name[0]-'A' + 1) * 27 * 27  +
(name[1]-'A' + 1)  * 27 +
(name[2]- 'A' + 1) ;
}

char* int2str(int num)
{
char* name2 = (char*)malloc(sizeof(char)*4);
int a = num / (27*27) ;
int b = num / 27 - a*27;
int c = num % 27 ;
name2[0] = a + 'A' - 1 ;
name2[1] = b + 'A' - 1 ;
name2[2] = c + 'A' - 1 ;
name2[3] = '\0' ;
return name2;
}

map<int , int> fri_no ;

vector<cust> vv;

int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
int i, L;
char name[4];
for(i=1;i<=m;i++)
{
scanf("%d",&L);
while(L--)
{
scanf("%s",name);
int int_name = str2int(name);
fri_no[int_name] = i ;
}
}
int first_time = 0 ;
cust ctmp ;
for(i=1;i<=n;i++)
{
scanf("%s %d %d", name , &ctmp.T,&ctmp.P) ;
if(ctmp.P > 60)
ctmp.P = 60 ;
ctmp.int_name = str2int(name) ; // 字符串name转换成int型name
ctmp.come_no = i ;

//if(i == 1 ) // 第一位顾客不用等待
//{
//	first_time = ctmp.T ;
//	ctmp.T = 0 ;
//}else{
//	ctmp.T -= first_time ;
//}
vv.push_back(ctmp) ;
}
int out_count = 0; //完成服务的顾客数目
int pre_out_int_name ; // 上一个服务顾客的int_name
int now_time = 0 ; // 当前时刻
int total_wait_time = 0 ;//总共的等待时间
while(out_count < n)
{
if(out_count == 0)
{
cust now_cust = vv.at(0);
vv.erase(vv.begin());

pre_out_int_name = now_cust.int_name ;
total_wait_time = 0 ;
now_time = now_cust.T + now_cust.P ;
}else{
int tmp_fri_num = fri_no[pre_out_int_name] ; //朋友圈编号
int place = 0;
cust next_cust = vv.at(0);
for(int j = 0 ;j < (int)vv.size() ; j ++)
{
cust cust_tmp = vv.at(j) ;
int cust_tmp_fri_num = fri_no[cust_tmp.int_name];
if(cust_tmp.T <= now_time && cust_tmp_fri_num == tmp_fri_num && tmp_fri_num != 0)
{
next_cust = cust_tmp ;
place = j ;
break;
}
}

vv.erase(vv.begin() + place) ; //删除已经服务的顾客

if(next_cust.T > now_time) //如果 到达时间大于 当前时间
{
now_time = next_cust.T + next_cust.P ;
total_wait_time += next_cust.T ;
}else{
total_wait_time += (now_time - next_cust.T);
now_time += next_cust.P ;
}
pre_out_int_name = next_cust.int_name ;
}
out_count++;
printf("%s\n",int2str(pre_out_int_name)); //顺序打印名字
}
printf("%.1f\n",(1.0*total_wait_time)/n);
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: