NYOJ 题目511 移动小球(双向循环链表)



http://acm.nyist.net/JudgeOnline/problem.php?pid=511

移动小球

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 2
描述
给你n个小球,从左到右编号依次为1,2,3,4,5,6.........n,并规定小球1的左边的球号为n,小球n的右边的球号为1.现在有以下3种操作:A x y表示把编号为x小球移动到编号为y的小球的左边,B x y表示把编号为x小球移动到编号为y的小球的右边,Q 1 m为询问编号为m的小球右边的球号,Q 0 m为询问编号为m的小球左边的球号。
输入
第一行有一个整数n(0<n<10000),表示有n组测试数据,随后每一组测试数据第一行是两个整数N,M,其中N表示球的个数(1<N<10000),M表示操作的的次数(0<M<10000)
随后的M行,每行有三个数 s x y,s表示操作的类型,x,y为小球号。当s为Q时,若x为1,则询问小球y右边的球号,x为0,则询问小球y左边的球号。
输出
输出每次询问的球号
样例输入
1
6 3
A 1 4
B 3 5
Q 1 5
样例输出
3


注意:用以下形式结构体构建双向循环链表时,连接一个节点时要把该节点的左指针和前一个节点的右指针同时连起来 ,否则构建双向循环链表不成功。

struct Node
{
     int data;
    struct Node *llink,*rlink;
}num[MAX+10];

#include<stdio.h>
#define MAX 10000
struct Node 
{
	int data;
	struct Node *llink,*rlink;
}num[MAX+10];
struct Node *L,*R,*p;
void Build(int n)
{//用结构体链表构建双向循环链表时,连接一个节点时要把该节点的左指针和前一个节点的右指针同时连起来 
	int i;
    for(i=1;i<n;i++)  
    {  
        num[i].data=i;  
        num[i].rlink=&num[i+1];  
        num[i+1].llink=&num[i];  
    }  
    num[1].llink=&num[n];  
    num[n].rlink=&num[1];  
    num[n].data=n;

}
void A(int x,int y)
{
	//-----删除x节点-----// 
	p=&num[x];
	L=p->llink;
	R=p->rlink;
	L->rlink=R;
	R->llink=L;
	//-------------------//
	
	//-----将x移到y的左边-----//
	struct Node *s=&num[x];
	p=&num[y];
	L=p->llink;

    s->rlink=p;
	p->llink=s;
	s->llink=L;
	L->rlink=s;
	//------------------------// 
}
void B(int x,int y)
{
    //-----删除x节点-----// 
	p=&num[x];
	L=p->llink;
	R=p->rlink;
	L->rlink=R;
	R->llink=L;
	//-------------------//
	
	//-----将x移到y的右边-----//
	struct Node *s=&num[x];
	p=&num[y];
	R=p->rlink;

    s->rlink=R;
	R->llink=s;
    s->llink=p;
	p->rlink=s;
	//------------------------//
}
void Q(int x,int y)
{
    p=&num[y];
	if(x==0)
	printf("%d\n",p->llink->data);
	else if(x==1)
	printf("%d\n",p->rlink->data);	
}
int main()
{
	int N,n,m,i,x,y;
	char c;
	scanf("%d",&N);
	while(N--)
	{
		scanf("%d %d",&n,&m);
		Build(n);//创建双向循环链表
		
	
		
		while(m--)
		{
			getchar();
			scanf("%c %d %d",&c,&x,&y);
			if(c=='A')
			A(x,y);//将x移到y的左边 
			else if(c=='B')
			B(x,y);//将x移到y的右边
		    else if(c=='Q') 
			Q(x,y);
	    }
	}
	return 0;
}


(1)                                                            (2)

struct Node                                             struct Node  
{                                                               {
     int data;                                                    int data;
     struct Node *llink,*rlink;                         struct Node *llink,*rlink; 
};                                                              }num[10010];

上面代码定义链表节点时用的是(2),这样定义的好处是需要对某个节点操作时就可以直接操作,而如果用(1)方法定义,若想对某一个节点进行操作,必须从头结点一直找到想要操作的节点,增加了额外的时间,这就是(2)方法的优点。

下面的代码就是用(1)方法,在建立循环链表时,当需要新节点时就申请。但在对某个节点进行操作时,就要先找到该节点,这样就大大增加了时间,所以提交超时。把它也贴出来,提醒自己这两种定义的不同,以后要认真思考分析。

//因为没有考虑到在链表查找到某一元素时要进行线性遍历,所以超时 
#include<stdio.h>
#include<string.h>
#include<malloc.h>
struct Node
{//循环链表节点 
	int data;
	struct Node *llink;
	struct Node *rlink;	
};
int main()
{
	int N,n,m,i,j,k,x,y;
	char c;
	scanf("%d",&N);
	while(N--)
	{
		scanf("%d %d",&n,&m);
		//==========构造双向循环链表==========// 
		//-----创建头结点-----//
		struct Node *head;
		head=(struct Node *)malloc(sizeof(struct Node));
		head->data=1;
		head->llink=NULL;
		head->rlink=NULL;
		//--------------------//
		struct Node *p=head;
		
		for(i=1;i<=n;i++)
		{
			if(i==1) continue;
			else if(i>1&&i<=n)
			{
				//-----创建新节点-----//
				struct Node *s;
				s=(struct Node *)malloc(sizeof(struct Node));
				s->data=i;
				s->llink=NULL;
				s->rlink=NULL;
				//--------------------//
				p->rlink=s;
				s->llink=p;
				
				p=p->rlink; 
			}
		}
		p->rlink=head;
		head->llink=p;
		//==========构造双向循环链表成功==========//
		
		while(m--)
		{
			getchar();
			scanf("%c %d %d",&c,&x,&y);
			struct Node *L,*R; 
			if(c=='A')
			{
				p=head;
				while(!(p->data==x))              //(1)这里对链表遍历会超时 
				p=p->rlink;
				//-----删除X节点-----// 
				L=p->llink;
				L->rlink=L->rlink->rlink;
				R=p->rlink;
				R->llink=R->llink->llink; 
				//-------------------//
				
				//-----将x移到y的左边-----//
				p=head;
				while(!(p->data==y))              //(2)这里对链表遍历会超时  
			    p=p->rlink;
			    L=p->llink;
			    struct Node *s;
			    s=(struct Node *)malloc(sizeof(struct Node));
			    s->data=x;
			    
			    s->rlink=p;
			    p->llink=s;
			    s->llink=L;
			    L->rlink=s;
			    //------------------------//
		    }
		    else if(c=='B')
		    {
		    	p=head;
		    	while(!(p->data==x))              //(3)这里对链表遍历会超时    
		    	p=p->rlink;
		    	//-----删除X节点-----// 
				L=p->llink;
				L->rlink=L->rlink->rlink;
				R=p->rlink;
				R->llink=R->llink->llink; 
				//-------------------//
				
				//-----将x移到y的右边-----//
				p=head;
				while(!(p->data==y))               //(4)这里对链表遍历会超时 
			    p=p->rlink;
			    R=p->rlink;
			    struct Node *s;
			    s=(struct Node *)malloc(sizeof(struct Node));
			    s->data=x;
			    
			    s->rlink=R;
			    R->llink=s;
			    s->llink=p;
			    p->rlink=s;
			    //------------------------//
		    }
		    else if(c=='Q')
		    {
		    	p=head;
		    	while(!(p->data==y))                //(5)这里对链表遍历会超时 
		    	p=p->rlink;
		    	if(x==0)
		    	{
		    		p=p->llink;
		        }
		    	else if(x==1)
		    	{
		    		p=p->rlink;
		    	}
		    	printf("%d\n",p->data);
		    }
		}
    }
    return 0;
}
    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值