[HAOI2008]移动玩具

问题 A: [HAOI2008]移动玩具

时间限制: 1 Sec   内存限制: 162 MB
提交: 54   解决: 38
[ 提交][ 状态][ 讨论版]

题目描述

在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动
时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移
动到某人心中的目标状态。

输入

前4行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具。接着是一个空
行。接下来4行表示玩具的目标状态,每行4个数字1或0,意义同上。

输出

一个整数,所需要的最少移动次数。

样例输入

1111
0000
1110
0010

1010
0101
1010
0101

样例输出

4

 [HAOI2008]移动玩具

         额,装个逼,水题。

         考试的时候看到数据范围就想到了状压,但二维状压也不会啊……于是乎发现压16位也是可以的,于是乎神来之笔的压了16位,向上向下就是(1<<(i±4)),向左向右就是(1<<(i±1)),注意判断边界即可,简单的证明了一下宽搜的正确性后打了出来,A了……好吧确实少了点,不过就是这样,乱搞压正解。


 
 
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#define V 505
using namespace std;
char s[5][5],t[5][5];
bool vis[50];
int f[5][5],w[5][5],id,is;
int ans=V*V;
struct data
{
     int to,next,dis;  
}Edge[2*V];
int head[V],dep[V],sd[V],tot;
inline void add1( int x, int y, int z)
{
   Edge[tot].to=y;
   Edge[tot].dis=z;
   Edge[tot].next=head[x];
   head[x]=tot++;      
}
void dfs( int x, int num)
{
//  cout<<x
    if (x==id)
    {
          for ( int i=head[x];i!=-1;i=Edge[i].next)  
          {
                if (!vis[Edge[i].to])  
                {
                    ans=min(ans,num+Edge[i].dis);
                    return ;                     
                }    
          }     
    }
    else
    {
          for ( int i=head[x];i!=-1;i=Edge[i].next)  
          {
                if (!vis[Edge[i].to])  
                {
                    vis[Edge[i].to]=1;
                    dfs(x+1,num+Edge[i].dis);
                    vis[Edge[i].to]=0;                      
                }    
          }   
    }    
      
}
int main()
{
  // freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
  // freopen("movea.in","r",stdin); freopen("movea.out","w",stdout);
   memset (head,-1, sizeof (head));
   for ( int i=1;i<=4;i++)
    for ( int j=1;j<=4;j++)
   cin>>s[i][j];
   getchar ();
   for ( int i=1;i<=4;i++)
    for ( int j=1;j<=4;j++)
   {
      cin>>t[i][j];
     if (s[i][j]==t[i][j])
     s[i][j]=t[i][j]= '0' ;
   }
   for ( int i=1;i<=4;i++)
    for ( int j=1;j<=4;j++)
    {
        if (s[i][j]== '1' )
        f[i][j]=++id; 
        if (t[i][j]== '1' )
        w[i][j]=++is;
    }
   // return 0;
   int dis;
   for ( int i=1;i<=4;i++)
    for ( int j=1;j<=4;j++)
    if (s[i][j]== '1' )
    {
        for ( int x=1;x<=4;x++)
         for ( int y=1;y<=4;y++)     
         if (t[x][y]== '1' )
         {
           dis= abs (x-i)+ abs (y-j);
           add1(f[i][j],w[x][y],dis);
           //cout<<i<<" % "<<j<<endl;
           //cout<<x<<"  !"<<y<<endl;
         }      
    }
    dfs(1,0);
    if (ans==V*V)
    cout<<0;
    else
    cout<<ans<<endl;
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值