UVA 1414 - Hanoi Towers(dp)

The ``Hanoi Towers" puzzle consists of three pegs (that we will name A , B , and C ) with n disks of different diameters stacked onto the pegs. Initially all disks are stacked onto peg A with the smallest disk at the top and the largest one at the bottom, so that they form a conical shape on peg A .

\epsfbox{p4050.eps}

A valid move in the puzzle is moving one disk from the top of one (source) peg to the top of the other (destination) peg, with a constraint that a disk can be placed only onto an empty destination peg or onto a disk of a larger diameter. We denote a move with two capital letters - the first letter denotes the source disk, and the second letter denotes the destination disk. For example, AB is a move from disk A to disk B .

The puzzle is considered solved when all the disks are stacked onto either peg B (with pegs A and C empty) or onto peg C (with pegs A and B empty). We will solve this puzzle with the following algorithm.

All six potential moves in the game (ABACBABCCA, and CB) are arranged into a list. The order of moves in this list defines our strategy. We always make the first valid move from this list with an additional constraint that we never move the same disk twice in a row.

It can be proven that this algorithm always solves the puzzle. Your problem is to find the number of moves it takes for this algorithm to solve the puzzle using a given strategy.

Input 

Input contains several dataset. Each dataset contains two lines. The first line consists of a single integer number n (1$ \le$n$ \le$30) -- the number of disks in the puzzle. The second line contains descriptions of six moves separated by spaces - the strategy that is used to solve the puzzle.

Output 

For each dataset, write to the output file the number of moves it takes to solve the puzzle. This number will not exceed 1018 .

Sample Input 

3 
AB BC CA BA CB AC 
2 
AB BA CA BC CB AC

Sample Output 

7 
5
题意: 3个桩的汉诺塔,n个盘子,所有盘子起先都是在 A 上,给一个列表,6个成对的字母,表示移动方式,从头开始走那个表,找到第一个可以移动的方去移动,然后就退出,又从头开始走第二遍表。这里还有另外一个条件,就是同一个盘子不能被连续的移动两次, 最后让你输出步数。

思路:没推出来,看了别人题解,居然是去设 f[i] = f[i - 1] * x + y;然后利用模拟求前3项,然后就能求出x,y,然后递推即可。

代码:

#include <stdio.h>
#include <string.h>
#include <stack>
using namespace std;

int n, i;
long long f[35], x, y;
char str[6][3];

long long get(int n) {
	long long ans = 0;
	int fa = -1;
	stack<int> h[3];
	for (int i = n; i >= 1; i--)
		h[0].push(i);
	while (1) {
		for (int i = 0; i < 6; i++) {
			int s = str[i][0] - 'A', e = str[i][1] - 'A';
			if (!h[s].empty() && h[s].top() != fa && (h[e].empty() || h[s].top() < h[e].top())) {
				fa = h[s].top();
				h[e].push(h[s].top());
				h[s].pop();
				ans++;
				break;
			}
		}
		if (h[1].size() == n || h[2].size() == n)
			return ans;
	}
}

long long solve() {
	for (i = 1; i <= 3; i++)
		f[i] = get(i);
	x = (f[2] - f[3]) / (f[1] - f[2]);
	y = f[2] - x * f[1];
	for (i = 4; i <= n; i++) {
		f[i] = x * f[i - 1] + y;
	}
	return f[n];
}

int main() {
	while (~scanf("%d", &n)) {
		for (int i = 0; i < 6; i++)
			scanf("%s", str[i]);
		printf("%lld\n", solve());
	}
	return 0;
}


有个找规律的思路,我队友想的:http://blog.csdn.net/keshuai19940722/article/details/21454489 这个做法应该是比较科学的。

一共只有3种情况。每种情况对应一个方程

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
int n;
string str[6];

string get() {
	string ans = "";
	char s = 'A';
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 6; j++) {
			if (str[j][0] == s) {
				ans += s;
				s = str[j][1];
				break;
			}
		}
	}
	return ans;
}

long long solve(int d) {
	long long x, y, ans = 1;
	n--;
	if (d == 0)
		x = 3, y = 2;
	else if (d == 1)
		x = 2, y = 1;
	else 
		x = 3, y = 0;
	while (n--) ans = ans * x + y;
	return ans;
}

int main() {
	while (~scanf("%d", &n)) {
		for (int i = 0; i < 6; i++)
			cin >> str[i];
		string v = get();
		if (v == "ACAC" || v == "ABAB")
			printf("%lld\n", solve(0));
		else if (v == "ACBC" || v == "ABCB")
			printf("%lld\n", solve(2));
		else
			printf("%lld\n", solve(1));
	}
	return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值