UVa 540 小团体队列

题意:队列中有小团体(队列)。当入队时,如果有该团体的元素在队列中,则新元素排到该团体的尾部,否则排到队列的尾部。出队时和正常的一样,队首元素出列。

思路:这个用STL很好模拟,用纯C的话,很直接会想到用二维数组来做,每个团体是其中的一个一维数组,最多再开一个数组来对小团体编号进行排队。但是当时没有看到题目中说的每个团体最后有1000个元素,这样的话我以为要开1000X200000的数组,忒大了~  

然后用的链表来实现。这里仍然是避免了指针和动态分配内存等易出错的东西,(不过这个方法还是把自己弄晕了点~)用大数组来模拟。首先申请的MAXN个Node的数组anode即是这里最后会用到的Node数,cnt来计数。然后team数组是保存元素i的团体编号team[i],iindex数组是保存每个团体i在队列中最后一个元素的anode下标。然后front和rear指向这个逻辑上的队列的队首和队尾元素。每次入队出队时维护上述信息即可。调了几次才调通,总是会忽略一些情况,注释里有。

注意:index是string.h中的一个函数,在本地可通过,交到OJ上就CE了。所以改成了iindex。 

           开始以为输入数据是给了类别编号,看第一个示例,有两个3号类,就不能理解了。问了才发现那个3是该类个数,不是类别编号。所以,要看清题目,及题目要求,特别是对样例困惑的时候。

           遇到WA时,可以构造大一点的数据来测试。(比如开始把cnt当rear指针用,很多示例都过得了,多测几种数据才发现错误)

开始以为这是水题,在发现数组做不了(忽略了每个团体最多1000个元素)时,发现这个还是有些难度的,虽然题意清晰,就像现实中的插队一样,但是实现起来还是有些麻烦的。  感觉最简单的C做可能就是数组了吧

Code:

<pre name="code" class="cpp">#include<stdio.h>
#include<string.h>
#define MAXN  200010

struct Node
{
 int data;
 int next;      
};

Node anode[MAXN];
int team[1000010];//相当于hash表,元素i在team[i]团体里 
int cnt=0;//anode数组使用最大的计数,anode[0]不用,作为空元素 
int iindex[1010];//每个小团体在队列中尾元素的anode数组编号 
//int que[MAXN];//题中描述的队列,入队的是在anode数组编号
int front=1,rear=0;//终指向团体队列的队首,队尾。注意这里rear不能用cnt代替,两者不同 

int main()
{
 //freopen("540.in","r",stdin);
 //freopen("540.out","w",stdout); 
 int t;
 int n=1;
 while((scanf("%d",&t)==1)&&t)
 {
  printf("Scenario #%d\n",n++);
  memset(iindex,0,sizeof(iindex));
  memset(team,0,sizeof(team));
  cnt=0;front=1;
  for(int i=0;i<t;++i)
  {
   int num=0,a=0;
   scanf("%d",&num);
   for(int j=0;j<num;++j)
   {
    scanf("%d",&a);
    team[a]=i;       
   }
  }
  //input command
  char cmd[25];
  while(scanf("%s",cmd)==1)
  {
   if(cmd[0]=='E')
   {//入队,需要维护队尾 
    int b=0;
    scanf("%d",&b);
    anode[++cnt].data=b;
    if(iindex[team[b]]==0)//是该团体第一个元素
    {
     anode[cnt].next=0;                                        
     iindex[team[b]]=cnt;
     anode[rear].next=cnt;//将新团体的第一个元素附在队尾 
     rear=cnt;//新团体元素必是队尾。 
    }              
    else
    {//该团体已有元素在队中 
     if(iindex[team[b]]==rear) rear=cnt;//若该团体在队尾,则新增的元素即成为队尾。 
     //在该团体尾元素后插入新结点,并维护iindex 
     int x=anode[iindex[team[b]]].next;
     anode[iindex[team[b]]].next=cnt;
     anode[cnt].next=x;   
     iindex[team[b]]=cnt;
    }
   }//ifcmd
   else if(cmd[0]=='D')
   {//出队,需要维护队首 
    printf("%d\n",anode[front].data);
    //判断该元素是否是该团体的尾元素,维护iindex
    int type=team[anode[front].data];
    if(iindex[type]==front) iindex[type]=0;
     
    front=anode[front].next;
    if(front==0) front=cnt+1;//当队列为空时,front应为下一个新结点的anode中编号 
   }           
   else
    break;             
  }//while  
  printf("\n");                           
 }
 return 0;   
}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值