luogu P4289 [HAOI2008]移动玩具

传送门

这道题可以二进制记录状态搜索

也可以做以下考虑

若一个棋子要移动到另一个位置上去,则步数为两点的曼哈顿距离(横坐标差的绝对值+纵坐标差的绝对值),因为假设路径上有其他的棋子,可以通过移动其他棋子,做到等价于这个棋子无视其他的棋子直接走到目标点

举个栗子

(egin{matrix}0&1&0\0&1&1\0&1&0end{matrix}=>egin{matrix}0&1&0\1&1&0\0&1&0end{matrix})

只要2步,右边那个可以无视其他棋子直接移动到左边

然后把已经是目标状态的位置清零(减少搜索层数?),然后搜索每个棋子移到哪个位置

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define abs(a) ((a)<0?-(a):(a))

using namespace std;
const int N=4;
il LL rd()
{
    re LL x=0,w=1;re char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int a[N][N],b[N][N],p[N*N][2],tt,ans=233;
il void dfs(int o,int s)
{
  if(s>=ans) return;
  if(o>tt) {ans=s;return;}
  for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
      if(b[i][j])
    	{
    	  b[i][j]=0;
    	  dfs(o+1,s+abs(p[o][0]-i)+abs(p[o][1]-j));
    	  b[i][j]=1;
    	}
}

int main()
{
  char ss[N];
  for(int i=0;i<4;i++)
    {
      scanf("%s",ss);
      for(int j=0;j<4;j++) a[i][j]=ss[j]^48;
    }
  for(int i=0;i<4;i++)
    {
      scanf("%s",ss);
      for(int j=0;j<4;j++)
    	{
    	  b[i][j]=ss[j]^48;
    	  if(a[i][j]&b[i][j]) a[i][j]=b[i][j]=0;
    	}
    }
  for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
      if(a[i][j]) p[++tt][0]=i,p[tt][1]=j;
  dfs(1,0);
  printf("%d
",ans);
  return 0;
}

原文地址:https://www.cnblogs.com/smyjr/p/9608635.html