例题6-5 移动盒子(Boxes in aline, UVa 12657)

原题链接:https://vjudge.net/problem/UVA-12657
分类:链表
备注:双向循环链表

都是看着紫书的提示和一些比较关键的代码才一步步做出来的。
这应该算是个好题吧,链表的使用要注意的细节很多。
要注意初始化成一个双向循环链表,这样保证每次调换位置和头尾相关时不会出现错误,以0为哨位节点以便于计算ans时要进行的遍历操作。
link函数连接两个结点,关键是要每次执行命令之前把X,Y的左右结点存储下来,在此基础上使用link函数可以使得代码变得简单易懂,也不容易犯错。
计算ans时,先计数再判断奇偶性的这种操作是最好的,奇数两种顺序算结果相同,偶数则要错位一下。如果直接通过是否反转去计算的答案是错的。

代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int L[maxn], R[maxn];
void link(int lef, int rig) {
	R[lef] = rig; L[rig] = lef;
}
int main(void) {
	int n, m, kase = 0;
	while (~scanf("%d %d", &n, &m)) {
		for (int i = 1; i <= n; i++) {//0为哨位节点,构建循环双向链表
			L[i] = i - 1; 
			R[i] = (i + 1) % (n + 1);
		}
		R[0] = 1; L[0] = n;
		bool rev = 0;//反转标记
		for (int i = 0; i < m; i++) {
			int cmd; scanf("%d", &cmd);
			if (cmd == 4) { rev = !rev; continue; }
			int X, Y;
			scanf("%d %d", &X, &Y);
			int LX = L[X], RX = R[X], LY = L[Y], RY = R[Y];
			if (cmd < 3) {
				if (rev)cmd = 3 - cmd;
				if (cmd == 1 && L[Y] != X) {
					link(LX, RX); link(LY, X); link(X, Y);
				}
				else if (cmd == 2 && R[Y] != X) {
					link(LX, RX); link(X, RY); link(Y, X);
				}
			}
			else if (cmd == 3) {
				if (L[Y] == X) {
					link(LX, Y); link(X, RY); link(Y, X);
				}
				else if (R[Y] == X) {
					link(LY, X); link(Y, RX); link(X, Y);
				}
				else {
					link(LY, X); link(X, RY);
					link(LX, Y); link(Y, RX);
				}
			}
		}
		long long ans = 0;
		for (int i = 1, b = 0; i <= n; i++) {
			b = R[b];
			if (i % 2 == 1) ans += b;
		}
		if (rev && n % 2 == 0)ans = (1LL * n * (1LL * n + 1)) / 2 - ans;//仅有n为偶数时要换算
		printf("Case %d: %lld\n", ++kase, ans);
	}
	return 0;
}
发布了104 篇原创文章 · 获赞 97 · 访问量 4515

猜你喜欢

转载自blog.csdn.net/TK_wang_/article/details/105343137
今日推荐