UVA-12657 Boxes in a Line (模拟,双向链表(数组实现))

版权声明:个人学习笔记记录 https://blog.csdn.net/Ratina/article/details/83752033

第一次对数组实现双向链表的练习,理解了发现数组实现真方便…

题目:UVA-12657

题目描述:
你有n个盒子在桌子上的一条线上从左到右编号为1……n。你的任务是模拟四种操作

1 X Y 移动盒子编号X到盒子编号Y的左边(如果X已经在Y的左边了就忽略)

2 X Y 移动盒子编号X到盒子编号Y的右边(如果X已经在Y的右边了就忽略)

3 X Y 交换盒子编号X与盒子编号Y的位置

4 将整条线反转

操作保证合法,X不等于Y

举一个例子,如果n=6,操作 1 1 4然后就变成了2 3 1 4 5 6;再操作 2 3 5就变成了 2 1 4 5 3 6;再操作 3 1 6 就变成 2 6 4 5 3 1;最后操作4,就变成了 1 3 5 4 6 2

分析:
这题用数组实现双向链表极其便利,因为这里的编号从1~n,即是 值 ,也是 下标(可以理解为node的地址),所以不需要另外创建node数组来联系这两者,直接就能处理。

分析一下题目,1,2操作直接模拟即可,3操作最好要对X,Y相邻的情况进行特判(不知道其他方法是否可省略特判,反正我WA了 )。

操作4最为关键,如果每次都反转会花很多时间,一开始还不知道怎么处理,但其实反转只会影响操作1和操作2以及最后求和,如果反转了,操作1就变成了操作2,操作2变成了操作1,求和找奇数位置时从头到尾遍历变成从尾到头。

(还有,如果用switch语句来选择操作数,记得每个case结尾break;,不要问我为什么说这个

贴下代码(里面还有注释):

#include<cstdio>
using namespace std;
int Right[100001], Left[100001];
void link(int L, int R)    //构造一个函数来连接左右两个,可以让程序简洁明了很多
{
	Right[L] = R;
	Left[R] = L;
}
int main()
{
	int n, m,kase=1;
	while (scanf("%d%d",&n,&m)!=EOF)
	{
		int i, k, x, y,head,tail;
		bool flag = true;         //用来标记操作4,true不反转,false反转
		for (i = 1; i <=n; i++)   //i即是编号,又是下标,直接串成双向链表
			link(i - 1, i);
		head = 0;                 //head做头节点
		Left[head] = 0;
		tail = n + 1;             //这个tail还是很重要的,不然链表第n个的操作就不方便了
		link(n, tail);
		Right[tail] = 0;
		while (m--)
		{
			scanf("%d", &k);
			if (flag==false)      //当发现反转,仅影响操作1、操作2
			{
				if (k == 1)
					k = 2;
				else if (k == 2)
					k = 1;
			}
			switch (k)
			{
			    case 1:
				{
					scanf("%d%d", &x, &y);
					if (Left[y] == x)
						break;
					else
					{
						link(Left[x], Right[x]);
						link(Left[y], x);
						link(x, y);
					}
					break; 
				}
				case 2:
				{	
					scanf("%d%d", &x, &y);
					if (Right[y] == x)
						break;
					else
					{
						link(Left[x], Right[x]);
						link(x, Right[y]);
						link(y, x);
					}
					break; 
				}
				case 3:                     //注意特判相邻情况
				{
					scanf("%d%d", &x, &y);
					if (Right[x] == y)
					{
						link(x, Right[y]);
						link(Left[x], y);
						link(y, x);
					}
					else if (Left[x] == y)
					{
						link(y, Right[x]);
						link(Left[y], x);
						link(x, y);
					}
					else
					{
						int xleft = Left[x], xright = Right[x], yleft = Left[y], yright = Right[y];
						link(yleft, x);    //把x,y的左右都暂存,这样方便些,不然移动过程会发生变动
						link(x, yright);
						link(xleft, y);
						link(y, xright);
					}
					break;
				}
				case 4:flag = !flag;    //反转
			}
		}
		long long sum = 0;
		if (flag==true)    //正序查找奇数位置,从head到tail
		{
			i = Right[head];
			while (1)
			{
				sum += i;
				if (Right[i] == tail)
					break;
				else
					i = Right[i];
				if (Right[i] == tail)
					break;
				else
					i = Right[i];
			}
		}
		else             //反转后倒序查找奇数位置,从tail到head
		{
			i = Left[tail];
			while (1)
			{
				sum += i;
				if (Left[i] == head)
					break;
				else
					i = Left[i];
				if (Left[i] == head)
					break;
				else
					i = Left[i];
			}
		}
		printf("Case %d: %lld\n",kase++,sum);
	}
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/83752033
今日推荐