2016 UESTC Training for Data Structures M - 卿学姐失恋了Ⅱ CDOJ 1350 汉诺塔 模拟

M - 卿学姐失恋了Ⅱ

给你一个合法的汉诺塔状态,问你能否在M秒之内把他们都放到一根柱子上,圆盘总数是20

首先我们可以知道,我们最后要放到的那根柱子一定是0号盘子,就是最大的盘子,所在的柱子,为什么这样呢,因为不这样的话,我们就要移动0号盘子,我们想移动0号盘子,那么其他所有的盘子都必须移到某一根柱子上,这时我们可以把0号盘子移到另一根柱子上,然后再把其他所有的盘子移到0号盘子所在的柱子上,这样显然是不如把所有盘子移到0号盘子上所花时间短的(具体证明的话,我们可以假设移动每个盘子都花的时间是最长的时间,就是它上面全都叠满了盘子的情况,然后发现把这些时间总和加起来,才是之前那个的第二步,就是把其他所有盘子移到0号盘子所在的新位置),所以肯定不如固定0号盘子

 

现在我们知道了最终状态后,可以考虑最终状态往初始状态推的最少步数,这个比较好考虑

首先,0号肯定是不用动的,然后这个时候所以的盘子都在0号上,我们找到最大的不应该在这根柱子上的盘子,我们要把它移到它的目标柱子,这个过程的最短步数,就是把它移到目标柱子,这时所以比它小的盘子在另外一根柱子上,然后我们继续从大向小的检查盘子是否在所该在的柱子上,然后模拟移动情况,记录时间就行

最后把总时间和M做个比较就可以啦


代码:

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <set>
using namespace std;
#define ll long long
int a[12], pow_2[22], sta[4][22];
int pos_other(int a, int b)
{
	if (a == 1)
	{
		if (b == 2)
			return 3;
		else if (b == 3)
			return 2;
	}
	if (a == 2)
	{
		if (b == 1)
			return 3;
		else if (b == 3)
			return 1;
	}
	if (a == 3)
	{
		if (b == 2)
			return 1;
		else if (b == 1)
			return 2;
	}
	return 0;
}
int hanoi(int num, int pos, int aim)
{
	int pos1 = pos_other(pos, aim);
	for (int i = 0; i < 22; ++i)
	{
		if (sta[pos][i] == num)
		{
			for (int j = 0; j < 22; ++j)
			{
				if (sta[pos][i + j] != 0)
					sta[pos][i + j] = 0;
				else
					break;
			}
			for (int j = 0; j < 22; ++j)
			{
				if (sta[pos1][j] == 0)
				{
					for (int k = num + 1; k <= 20; ++k)
						sta[pos1][j + k - num - 1] = k;
					break;
				}
			}
			break;
		}
	}
	for (int i = 0; i < 22; ++i)
	{
		if (sta[aim][i] == 0)
		{
			sta[aim][i] = pos;
			break;
		}
	}
	return pow_2[20 - num];
}
int main()
{
	//freopen("input.txt", "r", stdin);
	pow_2[0] = 1;
	for (int i = 1; i <= 21; ++i)
		pow_2[i] = pow_2[i - 1] << 1;
	int t, ans = 0;
	scanf("%d", &t);
	for (int i = 1; i <= 20; ++i)
		scanf("%d", &a[i]);
	int pos = a[1];
	for (int i = 1; i <= 20; ++i)
		sta[pos][i - 1] = i;
	for (int i = 2; i <= 19; ++i)
	{
		if (pos == a[i])
			continue;
		ans += hanoi(i, pos, a[i]);
		//printf("%d %d\n", i, ans);
		pos = pos_other(pos, a[i]);
	}
	if (a[20] != pos)
	{
		for (int i = 22; i >= 0; --i)
			if (sta[pos][i] == 20)
			{
				sta[pos][i] = 0;
				break;
			}
		for (int i = 0; i < 22; ++i)
			if (sta[a[20]][i] == 0)
			{
				sta[a[20]][i] = 20;
				break;
			}
		++ans;
	}
	//printf("%d\n", ans);
	if (ans > t)
		printf("NO\n");
	else
		printf("YES\n");
	//system("pause");
	//while (1);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值