骑士精神(BZOJ1085) 题解

7 篇文章 0 订阅
5 篇文章 0 订阅
【问题描述】

    在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。

【样例输入】

    2
    10110
    01*11
    10111
    01001
    00000
    01011
    110*1
    01110
    01010
    00100

【样例输出】

    7
    -1

【解题思路】

    这题为SCOI2005的题,首先看到这一题,以为是广搜,结果发现搜索树太大了,用队列会炸,于是想到了迭代加深。

    把答案作为加深的对象,不断的对答案+1,然后我们可以利用估价函数减小搜索的范围,其实就打一个深搜出来就行了。

【代码实现】

 

 1 const en:array[1..5] of string=('11111','01111','00*11','00001','00000');
 2       dx:array[1..8] of longint=(2,-2,1,1,-1,-1,2,-2);
 3       dy:array[1..8] of longint=(1,1,-2,2,-2,2,-1,-1);
 4 var a:array [1..5] of string[5];
 5     h,r,i,n,j,w,ans,mini,x,y:longint;
 6 procedure swap(var x,y:char);
 7 var ch:char;
 8 begin
 9  ch:=x;
10  x:=y;
11  y:=ch;
12 end;
13 procedure dfs(x,y,dep,last:longint);
14 var i,j,d,xx,yy:longint;
15 begin
16  d:=0;
17  if mini<>-1 then
18   exit;
19  for i:=1 to 5 do
20   for j:=1 to 5 do
21    if a[i,j]<>en[i,j] then
22     inc(d);
23  if d=0 then
24   begin
25    mini:=dep;
26    exit;
27   end;
28  if ans-dep<d-1 then
29   exit;
30  for i:=1 to 8 do
31   begin
32    if mini<>-1 then
33     break;
34    if i=9-last then
35     continue;
36    xx:=x+dx[i];
37    yy:=y+dy[i];
38    if (xx in[1..5])and(yy in[1..5]) then
39     begin
40      swap(a[x,y],a[xx,yy]);
41      dfs(xx,yy,dep+1,i);
42      swap(a[x,y],a[xx,yy]);
43     end;
44   end;
45 end;
46 begin
47  readln(w);
48  while w>0 do
49   begin
50    a[1]:='';a[2]:='';a[3]:='';a[4]:='';a[5]:='';
51    dec(w);
52    for i:=1 to 5 do
53     begin
54      readln(a[i]);
55      for j:=1 to 5 do
56       if a[i,j]='*' then
57        begin
58         x:=i;
59         y:=j;
60        end;
61     end;
62    mini:=-1;
63    for ans:=0 to 15 do
64     begin
65      dfs(x,y,0,-1);
66      if mini<>-1 then
67       break;
68     end;
69    if mini=-1 then
70     writeln(mini)
71    else
72     writeln(ans);
73   end;
74 end.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (树形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用树形dp来解决这个问,具体来说,我们可以将这个图看作是一棵树,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 树形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值