1.题目描述:
lv棋
时间限制 7s
在集训队中非常流行一种lv棋,这种棋的棋盘是一个n乘m的网格,双方分为进攻方和防守方。
防守方在棋盘上三个点摆下三个棋子(这三个棋子有先后顺序,摆下后位置不能改变),
进攻方需要选择一条路径从起点(0,0)走到终点(0,1),每次只能向只能上、下、左、右方向移动,且只能移动一个单位。进攻方经过每一个格子一次且仅一次,且依次吃掉三个防守方棋子最后走到终点才算完成一次“进攻”。
强神和森神现在打算玩这个游戏,森神摆放完防守棋子后,强神说我A了。森神为了cha掉强神于是要加入另外的约束:
进攻方的棋子必须在整个路径的1/4,2/4,3/4处分别吃掉三个防守棋子。(如果路径长度不是4的倍数则下取整)
强神又A了,他觉得这个很无聊,所以现在想让聪明的你计算一共一下有多少种方法来完成对森神的“进攻”。
输入
输入包含若干组测试用例,每组测试用例的第一行包含两个整数n和m(2<=n,m<=8),分别表示棋盘的长与宽,接下来一行有6个整数x1,y1,x2,y2,x3,y3, 0<=xi<n, 0<=yi<m, i=1,2,3代表森神三个棋子摆放的位置(保证(xi,yi)不在起点和终点)
最后一组包含两个0,代表输入结束
输出
输出从(0,0)出发,在整个路径的1/4,2/4,3/4处按输入的顺序吃掉三个棋子最后走到(0,1)的方法数。
样例输入
3 6
2 1 2 4 0 4
4 3
2 0 3 2 0 2
0 0
样例输出
Case 1: 2
Case 2: 0
提示:
对于第一组测试用例,如下图是一种方法,该路径在1/4处(18/4 = 4)吃掉(2,1),在2/4处(18x2/4=9)吃掉(2,4),在3/4处(18x3/4=13)吃掉(0,4)。
3.解题思路:
由于本题的输入数据不大,因此可以使用搜索+剪枝的方法解题。
考虑以下剪枝:
1. 没到1/4,2/4,3/4的步数时,一定不可以出现在防守棋子的格子上
2. 因为格子不能重复走,所以未走过的格子一定不能被分成两部分
3.如果当前步数加上该点到的下一个目标点的曼哈顿距离(最小距离)都大于要求的步数的话,那么就没有必要搜下去了。
4. 5000ms代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100100
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
int mp[9][9];
bool vis[9][9];
int n, m;
int dir[4][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
int cpx[5], cpy[5], cps[5];
int cpn[9][9];
int cnt;
void dfs(int sx, int sy, int step, int id)
{
if (step == cps[id])
{
if (cpn[sx][sy] == id)
id++;
else return;
}
else if (cpn[sx][sy] > 0)
return;
if (step == cps[4])
{
cnt++;
return;
}
if (step > cps[id])
return;
if (abs(cpx[id] - sx) + abs(cpy[id] - sy) + step > cps[id])
return;
vis[sx][sy] = 1;
for (int i = 0; i < 4; i++)
{
int dx = sx + dir[i][0];
int dy = sy + dir[i][1];
if (dx >= 0 && dx < n && dy >= 0 && dy < m && !vis[dx][dy])
{
if ((dx == 0 || vis[dx - 1][dy]) && (dx == n - 1 || vis[dx + 1][dy]) && (dy != 0 && !vis[dx][dy - 1]) && (dy != m - 1 && !vis[dx][dy + 1]))
continue;
if ((dx != 0 && !vis[dx - 1][dy]) && (dx != n - 1 && !vis[dx + 1][dy]) && (dy == 0 || vis[dx][dy - 1]) && (dy == m - 1 || vis[dx][dy + 1]))
continue;
dfs(dx, dy, step + 1, id);
}
}
vis[sx][sy] = 0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int kase = 0;
while (~scanf("%d%d", &n, &m), n + m)
{
cnt = 0;
memset(cpn, 0, sizeof(cpn));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= 3; i++)
{
scanf("%d%d", &cpx[i], &cpy[i]);
cpn[cpx[i]][cpy[i]] = i;
cps[i] = n*m*i / 4;
}
cpx[4] = 0;
cpy[4] = 1;
cpn[0][1] = 4;
cps[4] = n*m;
dfs(0, 0, 1, 1);
printf("Case %d: %d\n", ++kase, cnt);
}
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}