洛谷1242 新汉诺塔
原题链接
显然要先把较大的盘放到目标位置。
有一个很明显的贪心方案:
设当前要把第\(x\)大的盘子从\(A\)移到\(B\),则先把比\(x\)小的盘子全部移到\(C\)柱,再将第\(x\)大的盘子移到\(B\)柱,这样递归求解。
该种贪心方案在大多数情况都是最优的,但是有个大佬出了一个\(HACK\)数据,将该贪心方案\(HACK\)掉了。
以下是该数据
//输入
3
1 3
0
2 2 1
2 2 1
0
1 3
//正确输出
move 3 from A to B
move 1 from C to B
move 2 from C to A
move 1 from B to A
move 3 from B to C
5
//该贪心方案的错误输出
move 1 from C to A
move 2 from C to B
move 1 from A to B
move 3 from A to C
move 1 from B to C
move 2 from B to A
move 1 from C to A
7
这时,我们就需要考虑另一种可能为最优的方案:
设当前要把第\(x\)大的盘子从\(A\)移到\(B\),则先把比\(x\)小的盘子全部移到\(B\)上,再将\(x\)盘移到\(C\)柱,再将比\(x\)小的盘子全部移到\(A\)上,最后将\(x\)盘移到\(B\)上。
虽然在大多数情况都是第一种更优,但是当比\(x\)小的盘子已经全部在\(x\)盘的目标柱上,这时可能是第二种方案更优。
由于该种特殊情况只可能出现在第一步(因为第一步已经将比最大盘小的盘都移到一根柱上了),所以我们可以复制一遍数组,用第二种方案跑第一步,再用第一种方案接着跑,最后和全部用第一种方案取最小值输出即可。
这题使用递归来写会更简洁一点(不过我复制一遍函数、数组名显得很长很臭)。
#include<cstdio>
using namespace std;
const int N = 50;
struct dd{
int x;
char f, t;
};
dd an[N << 10], b_an[N << 10];
int a[N], b[N], b_a[N], b_b[N], s, b_s, k, b_k;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
void dfs(int x ,int y)
{
if (!(a[x] ^ y))
return;
for (int i = x - 1; i; i--)
dfs(i, 6 - a[x] - y);
an[++k].x = x;
an[k].f = a[x] + 'A' - 1;
an[k].t = y + 'A' - 1;
a[x] = y;
s++;
}
void b_dfs(int x ,int y)
{
if (!(b_a[x] ^ y))
return;
for (int i = x - 1; i; i--)
b_dfs(i, 6 - b_a[x] - y);
b_an[++b_k].x = x;
b_an[b_k].f = b_a[x] + 'A' - 1;
b_an[b_k].t = y + 'A' - 1;
b_a[x] = y;
b_s++;
}
void pr(int o, dd ans[])
{
for (int i = 1; i <= o; i++)
printf("move %d from %c to %c\n", ans[i].x, ans[i].f, ans[i].t);
}
int main()
{
int i, j, n, m, x;
n = re();
for (i = 1; i < 4; i++)
for (m = re(), j = 1; j <= m; j++)
{
x = re();
a[x] = b_a[x] = i;
}
for (i = 1; i < 4; i++)
for (m = re(), j = 1; j <= m; j++)
{
x = re();
b[x] = b_b[x] = i;
}
for (i = n - 1; i; i--)//模拟用第二种方案跑第一步
b_dfs(i, b_b[n]);
x = b_a[n];
b_dfs(n, 6 - b_a[n] - b_b[n]);
for (i = n - 1; i; i--)
b_dfs(i, x);
b_dfs(n, b_b[n]);
for (i = n - 1; i; i--)//接着全部用第一种方案
b_dfs(i, b_b[i]);
for (i = n; i; i--)//全部用第一种方案跑
dfs(i, b[i]);
pr(s > b_s ? b_k : k, s > b_s ? b_an : an);
printf("%d", s > b_s ? b_s : s);
return 0;
}
posted on 2018-10-19 20:15 Iowa_Battleship 阅读(165) 评论(0) 编辑 收藏 举报