[刷题之旅no10]UVA540 团体队列 Team Queue

该博客主要讨论了一道编程题目,涉及使用C语言实现一个队列数据结构,包括入队、出队和清空操作。博主详细阐述了算法思路,从读取队伍和队员信息,到处理各种指令,如添加新队员(E)、删除首队员(D)和清空队列(S)。代码中使用二维数组line和辅助变量记录队伍状态,并通过循环和条件判断实现队列操作。

好吧,算是一道难题吧。
思路:
1.读取队伍数,以次设置循环(如果队伍数等于0,直接终止循环)
2.读取每个队伍的人数,将读取到的队员编号,记录到一个数组之中,数组下标就是队员编号,对应的值为队员所在队伍
3.读取指令%s
4.如果开头是e,说明是入队
5.此时再读取入队人编号
6.如果此时队列是空的head==0,把这个入队人入队,放到head的位置,然后tail+1;同时找到这个人对应的队伍,将head记录为此时队伍的队尾编号,让将r_tail=head。
7.如果队列不是空的(如何判断队列不是空的呢?)
7.1如果队伍中有同队人,也就是队伍的队尾不等于0,
7.1.1如果当前同队人的队尾就是整个队伍的队尾
当前队伍的人的队尾的右端指向当前人,当前人的右端不管,r_tail=当前人,当前人入队,当前人的队伍的队尾改成tail,tail=tail+1;
7.1.2如果当前人同队人队尾不是整个队伍的尾端
那么当前人指向当前队尾人指向的人,当前人的队伍的队尾的人指向当前人,
当前人的队伍的队尾指向tail,tail=tail+1;
7.2如果队伍中没有同队人,也就是队伍的队尾等于0
那么就要直接将当前队员放在tail位置,更新队伍队尾为tail,让r_tail的人指向我,让后让r_tail等于tail,然后tail+1;
4.如果开头是d,说明首元素出列,出队的时候可是要按照队列顺序,而不是数组的下标顺序出队列!
5.如果当前没人了,说明当前的head=0,忽略此条操作
6.如果队伍中有人,也就是head!=0
6.1如果此时head下标的的队员所对应的队伍的队尾是自己,也就是这个队伍只剩下他一个人了,那么将这个元素对应队员对应队伍的队尾改成0,然后输出这个队员,head变成这个队员指向的位置。
6.2如果此时head下标对应的队员的队伍的队尾下标不等于head,说明此时输出队员编号,令head等于当前队员指向的那个坐标,
4.如果开头是S
那么清空所有数值,从新来过
ok,这道题终于算是解决了,谁能想到最后一个换行符还花了我10分钟去查呢。。。
查看答案:大佬们用的都是队中队的方法,记录每个队伍的优先级,然后进行弹出,插入即可。得益于c++的方便性,这里就不想在c语言中怎么实现了
再来捋一遍思路:(分支)
4.若e入
若没有队伍中的人
若有队伍中的人
若队伍中的人是队列尾
若队伍中的人不是队列尾
若d出
若空
若有人
若这个人是团队结尾
若这个人不是团队结尾
若s
ok分支完成,以后分支的时候,先把比较“大”的判断完成,然后再处理比较小的细节,即经过判断之后如何处理,最后还可以稍微优化一下代码。
代码:

#include<stdio.h>
int line[1000005][2]={0},head=0,tail=1,r_tail=0,tn=0,tm=0,no=0,cnt=0,mt[1000000]={0}; 
int main()
{
	while(1)
	{
		//每次stop之后都要清空太麻烦,直接从新申请内存就好了 
		int t_end[1005]={0};
		char oprate[10];
		scanf("%d",&tn);
		if(tn==0)
		{
			break;//没有队伍了,终于结束了啊! 
		} 
		cnt++;
		printf("Scenario #%d\n",cnt);//输出他要的 
		for(int i=1;i<=tn;i++)//tn个队伍循环 
		{
			scanf("%d",&tm);//记录队员
			for(int j=1;j<=tm;j++)
			{
				scanf("%d",&no);//读取编号
				mt[no]=i;//记录每个编号所对应的队伍 
			}
		}
		//读取完毕
		//现在开始读取指令,由于读取指令没有停止,所以继续奥。 
		while(1)
		{
			scanf("%s",oprate);
			//判断oprate的情况 
			if(oprate[0]=='E')//入队
			{
				scanf("%d",&no);//读取入队人
				if(head==0)//空队伍
				{
					head++;
					line[head][0]=no;
					tail=tail+1;
					t_end[mt[no]]=head;
					r_tail=head;
				}
				else//不空
				{
					if(t_end[mt[no]]!=0)//说明队伍中有人
					{
						if(t_end[mt[no]]==r_tail)//整个队伍的尾端
						{
							line[tail][1]=line[t_end[mt[no]]][1];
							line[t_end[mt[no]]][1]=tail;
							t_end[mt[no]]=tail;
							line[tail][0]=no;
							r_tail=tail;
							tail=tail+1;
						} 
						else
						{
							line[tail][1]=line[t_end[mt[no]]][1];
							line[t_end[mt[no]]][1]=tail;
							t_end[mt[no]]=tail;
							line[tail][0]=no;
							tail=tail+1;
						}
						
					}
					else//说明队伍中没有同队人,此时上一个队尾元素应该指向你 
					{
						line[tail][0]=no;
						line[r_tail][1]=tail;
						t_end[mt[no]]=tail;
						r_tail=tail;
						tail=tail+1;
					}
				}
			}
			else if(oprate[0]=='D')//出队列 
			{
				if(head==0)//空队列
				{
					continue;
				}
				else//队列中有人 
				{
					if(t_end[mt[line[head][0]]]==head)//本队只剩我一个人了 
					{
						t_end[mt[line[head][0]]]=0;
						printf("%d\n",line[head][0]);
						head=line[head][1];
					}
					else//也就是有人
					{
						printf("%d\n",line[head][0]);
						head=line[head][1];
					}
				}
			}
			else if(oprate[0]=='S')
			{
				head=0;
				tail=1;
				r_tail=0;
				printf("\n");
				break; 
			}
		} 
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值