91 棋盘游戏

91 棋盘游戏

作者: xxx时间限制: 1S章节: 宽度优先搜索

问题描述 :

大小为3的棋盘游戏里有3个白色棋子,3个黑色棋子,和一个有7个格子一线排开的木盒子。3个白棋子被放在一头,3个黑棋子被放在另一头,中间的格子空着。

初始状态: WWW_BBB

目标状态: BBB_WWW

在这个游戏里有两种移动方法是允许的:

  1. 你可以把一个棋子移到与它相邻的空格;

  2. 你可以把一个棋子跳过一个(仅一个)与它不同色的棋子到达空格。

大小为N的棋盘游戏包括N个白棋子,N个黑棋子,还有有2N+1个格子的木盒子。

这里是3-棋盘游戏的解,包括初始状态,中间状态和目标状态:

WWW BBB

WW WBBB

WWBW BB

WWBWB B

WWB BWB

W BWBWB

WBWBWB

BW WBWB

BWBW WB

BWBWBW

BWBWB W

BWB BWW

B BWBWW

BB WBWW

BBBW WW

BBB WWW

请编一个程序解大小为N的棋盘游戏(1 <= N <= 12)。要求用最少的移动步数实现。

输入说明 :

一个整数N。

输出说明 :

用空格在棋盘的位置(位置从左到右依次为1, 2, …, 2N+1)表示棋盘的状态。输出棋盘的状态变换序列,每行20个数(除了最后一行)。 输出的解还应当有最小的字典顺序(即如果有多组移动步数最小的解,输出第一个数最小的解;如果还有多组,输出第二个数最小的解;…)。

输入范例 :

9
输出范例 :

9 11 12 10 8 7 9 11 13 14 12 10 8 6 5 7 9 11 13 15
16 14 12 10 8 6 4 3 5 7 9 11 13 15 17 18 16 14 12 10
8 6 4 2 1 3 5 7 9 11 13 15 17 19 18 16 14 12 10 8
6 4 2 3 5 7 9 11 13 15 17 16 14 12 10 8 6 4 5 7
9 11 13 15 14 12 10 8 6 7 9 11 13 12 10 8 9 11 10

刚开始看这道题毫无头绪。N<=12,心想着可能又是搜索+剪枝。于是我就直接打开NOCOW上的题解。

太神了!一大牛的找规律把握吓傻了!

Usaco在这题上并没有指明不可以用分析法,而且dfs肯定TLE,所以我们取巧。

先观察样例数据,如果把还没移动的那一步也算上,那么空格的位置为

4 3 5 6 4 2 1 3 5 7 6 4 2 3 5 4 (n=3,样例)

5 4 6 7 5 3 2 4 6 8 9 7 5 3 1 2 4 6 8 7 5 3 4 6 5 (n=4)

我们凭借极其敏锐的眼光发现这组序列为

435 642 1357 642 35 4 (n=3,样例)

5 46 753 2468 97531 2468 753 46 5 (n=4)

即长度为1,2,3,4,...,n,n+1,n,...,4,3,2,1这样的2n+1组等差序列

我们讨论第1~n+1组序列,这些序列满足

  *公差的绝对值为2

  *奇数组为降序列,偶数组为升序列

  *对于第i组(1<=i<=n+1),若为奇数组则首项为n+i,偶数组则首项为n-i+2

对于第n+2~2n+1组,可以由对称性求出。了!一大牛的找规律把握吓傻了!

我就根据他那强大的公式编了个程序,然后0.000s秒过。。
于是我开始想了,汉诺塔问题有规律吗?……
#include<stdio.h>
int res[1010];
int n,tot,len;
 
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n+1;i++)//i表示组数
	{
		if (!(i%2))//奇数组
			for (int j=0;j<i;j++) res[++tot]=n-i+2+2*j;
		else//偶数组
			for (int j=0;j<i;j++) res[++tot]=n+i-2*j;
	}
	//输出
	for (int i=2;i<=tot;i++) 
	{
		len++;if (len%20==0) len=0;
		if (!len) printf("%d\n",res[i]);
		else {printf("%d ",res[i]);
		}
	}
	int num=(n*n+n)/2;
	int f=0;
	for (int i=n;i>=1;i--)
	{
		for (int j=(i*i-i)/2+1;j<=(i*i+i)/2;j++)//用的是等差数列的和,(首项+尾项)*项数/2,来输出对称的第i组数
		{
			f++;len++;if (len%20==0) len=0;
			if (!len) printf("%d\n",res[j]);
			else {
				printf("%d",res[j]);
		        if(f<num) printf(" ");
			}
		}
 
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值