第六章 数据结构基础(例题篇)--算法竞赛入门经典

本文深入讲解数据结构基础知识,包括双端队列、循环链表、双向链表等核心概念及应用实例,通过UVa竞赛题解析,提升算法理解和编程实践能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第六章 数据结构基础(例题篇)

例题6-1:并行程序模拟(Concurrency Simulator,UVa210) P139

双端队列:在中的双端队列deque
deque readyQ;
readyQ.push_front(1);//从队首插入元素
readyQ.push_back(2);//从队尾插入元素
int pid = readyQ.back();//取队尾元素
readyQ.pop_back();//弹出队尾元素
pid = readyQ.front();//取队首元素
readyQ.pop_front();//弹出队首元素
输入案例:
1
3 1 1 1 1 1 1
a = 4
print a
lock
b = 9
print b
unlock
print b
end
a = 3
print a
lock
b = 8
print b
unlock
print b
end
b = 5
a = 17
print a
print b
lock
b = 21
print b
unlock
print b
end

#include<cstdio>
#include<queue>
#include<cstring>
#include<cctype>
using namespace std;
const int maxn = 1000;

deque<int> readyQ;
queue<int> blockQ;
int n, quantum, c[5], var[26], ip[maxn];/*ip[pid]是程序pid的当前行号。
所有程序都存在prog数组,更类似真实的情况,代码也更短。*/
bool locked;
char prog[maxn][10];
void run(int pid)
{
	int q = quantum;
	while (q > 0)
	{
		char *p = prog[ip[pid]];
		switch (p[2])
		{
		case '=':
			var[p[0] - 'a'] = isdigit(p[5]) ? (p[4] - '0') * 10 + p[5] - '0' : p[4] - '0';
			q -= c[0];
			break;
		case 'i'://print
			printf("%d: %d\n", pid + 1, var[p[6] - 'a']);
			q -= c[1];
			break;
		case 'c'://lock
			if (locked)
			{
				blockQ.push(pid);
				return;
			}
			locked = true;
			q -= c[2];
			break;
		case 'l'://unlock
			locked = false;
			if (!blockQ.empty())
			{
				int pid2 = blockQ.front();
				blockQ.pop();
				readyQ.push_front(pid2);
			}
			q -= c[3];
			break;
		case 'd'://end
			return;

		}
		ip[pid]++;
	}
	readyQ.push_back(pid);
}
int main()
{
	freopen("input.txt", "rb", stdin);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d %d %d %d %d %d %d\n", &n, &c[0], &c[1], &c[2], &c[3], &c[4], &quantum);
		memset(var, 0, sizeof(var));
		int line = 0;
		for (int i = 0;i < n;i++)
		{
			fgets(prog[line++], maxn, stdin);
			ip[i] = line - 1;
			while (prog[line - 1][2] != 'd')
				fgets(prog[line++], maxn, stdin);
			readyQ.push_back(i);
		}
		locked = false;
		while (!readyQ.empty())
		{
			int pid = readyQ.front();
			readyQ.pop_front();
			run(pid);
		}
		if (T)
			printf("\n");
	}
	return 0;
}
例题6-2:铁轨(Rails,UVa514) P140

输入案例:
5
1 2 3 4 5
5 4 1 2 3
0
6
6 5 4 3 2 1
0
0
输出答案:
YES
NO

YES

#include<cstdio>
#include<stack>
using namespace std;
const int MAXN = 1000 + 10;
int n, target[MAXN];

int main()
{
	freopen("input.txt", "rb", stdin);
	while (scanf("%d", &n) == 1)
	{
		while (scanf("%d", &target[1]) == 1 && target[1] != 0)
		{
			stack<int> s;
			int A = 1, B = 1;
			for (int i = 2;i <= n;i++)
			{
				scanf("%d", &target[i]);
			}
			int ok = 1;
			while (B <= n)
			{
				if (A == target[B])
				{
					A++;
					B++;
				}
				else if (!s.empty() && s.top() == target[B])
				{
					s.pop();
					B++;
				}
				else if (A <= n)
					s.push(A++);
				else
				{
					ok = 0;
					break;
				}
				
			}
			printf("%s\n", ok ? "Yes" : "No");
		}
		printf("\n");
	}
	return 0;
}
例题6-4:破损的键盘(又名:悲剧文本)(Broken Keyboard,UVa11988) P143

循环链表
链表(linked list)
输入案例:
This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
输出答案:
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University

#include<iostream>
#include<string>
#include<stack>
using namespace std;

const int maxn = 100000 + 5;
int last, cur, nextlist[maxn];//光标位于cur号字符之后面
char s[maxn];
int main()
{
	freopen("input.txt", "rb", stdin);
	freopen("output.txt", "wb", stdout);
	while (scanf("%s", s + 1) == 1)
	{
		int n = strlen(s + 1);//输入保存在s[1],s[2]...中
		last = cur = 0;
		nextlist[0] = 0;
		for (int i = 1;i <= n;i++)
		{
			char ch = s[i];
			if (ch == '[')
				cur = 0;
			else if (ch == ']')
				cur = last;
			else
			{
				nextlist[i] = nextlist[cur];
				nextlist[cur] = i;
				if (cur == last)
					last = i;//更新“最后一个字符”编号
				cur = i;//移动光标
			}
		}
		for (int i = nextlist[0];i != 0;i = nextlist[i])
			printf("%c", s[i]);
		printf("\r\n");
	}
	return 0;
}
例题6-5:移动盒子(Boxes in a Line,UVa12657) P144

循环双向链表
双向链表(double linked list)
输入案例:
6 4
1 1 4
2 3 5
3 1 6
4
6 3
1 1 4
2 3 5
3 1 6
100000 1
4
输出答案:
Case 1: 12
Case 2: 9
Case 3: 2500050000

#include<iostream>
using namespace std;

const int maxn = 100000 + 5;
int n, leftlist[maxn], rightlist[maxn];

inline void link(int L, int R)
{
	rightlist[L] = R;
	leftlist[R] = L;
}

int main()
{
	freopen("input.txt", "rb", stdin);
	freopen("output.txt", "wb", stdout);
	int m, kase = 0;
	while (scanf("%d%d", &n, &m) == 2)
	{
		for (int i = 1;i <= n;i++)
		{
			leftlist[i] = i - 1;
			rightlist[i] = (i + 1) % (n + 1);
		}
		rightlist[0] = 1;
		leftlist[0] = n;
		int op, X, Y, inv = 0;
		while (m--)
		{
			scanf("%d", &op);
			if (op == 4)
				inv = !inv;
			else
			{
				scanf("%d%d", &X, &Y);
				if (op == 3 && rightlist[Y] == X)swap(X, Y);
				if (op != 3 && inv)op = 3 - op;
				if (op == 1 && X == leftlist[Y])continue;
				if (op == 2 && X == rightlist[Y])continue;
				int LX = leftlist[X], RX = rightlist[X], LY = leftlist[Y], RY = rightlist[Y];
				if (op == 1)
				{
					link(LX, RX);link(LY, X);link(X, Y);
				}
				else if (op == 2)
				{
					link(LX, RX);link(Y, X);link(X, RY);
				}
				else if (op == 3)
				{
					if (rightlist[X] == Y)
					{
						link(LX, Y);link(Y, X);link(X, RY);
					}
					else
					{
						link(LX, Y);link(Y, RX);link(LY, X);link(X, RY);
					}
				}
			}
		}
		int b = 0;
		long long ans = 0;
		for (int i = 1;i <= n;i++)
		{
			b = rightlist[b];
			if (i % 2 == 1)
				ans += b;
		}
		if (inv&&n % 2 == 0)
			ans = (long long)n*(n + 1) / 2 - ans;
		printf("Case %d: %lld\r\n",++kase,ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值