您的位置:首页 > 其它

HDU1067 Gap( BFS+ HASH 剪枝,矩阵用一个数表示)

2015-08-07 22:25 399 查看
题意:在4*8 的图中,给你4种类型的牌,每种牌序号1-7,比如42表示第4种牌的第二张,现在给你4*7一共28张,同时最左边的一列开始空的,第一步你要做的是把每种类型的1号牌从上到下放在这列空的位置上,然后在新出现的空位置,你要挑选空位子左边的那张牌的后继,如果没有的话,就不能操作。

解法:题目的状态很多,还有要怎么表示一个状态已经搜索过了呢。那就把矩阵做一下转化,把当前矩阵按行展开,以2为基数化为十进制的数(最大2^32,所以用Long Long),接下来存储这些整数,用map,set应该也可以,可能稍微慢点,我这里用简单的hash

#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<set>
#include<stack>
#define cl(a,b) memset(a,b,sizeof(a));
#define LL long long
#define P pair<int,int>
#define X first
#define Y second
#define pb push_back
#define out(x) cout<<x<<endl;
using namespace std;
const int maxn=25;
const int inf=9999999;
const int mod=100007;

struct node{
int x[4],y[4];//四个空格的位置
int a[4][8];//每一步的图的状态
int step;//步数
};
int aim[][8]={//目标的状态
{11,12,13,14,15,16,17,0},
{21,22,23,24,25,26,27,0},
{31,32,33,34,35,36,37,0},
{41,42,43,44,45,46,47,0}
};

vector<LL> hash_[mod];//hsah
void insert(LL key){//hash插入函数
int pos=(key%mod+mod)%mod;
hash_[pos].pb(key);
}
bool find(LL key){//hash查找函数
int pos=(key%mod+mod)%mod;
int N=hash_[pos].size();
for(int i=0;i<N;i++){
if(hash_[pos][i]==key)return true;
}
return false;
}

LL aimEncode=98430874871LL;///这个数是用encode函数计算aim数组所得到的
LL encode(int x[][8]){///把矩阵按行展开,接着以二为基数,化为十进制数,然后hash下
LL num=0;
for(int i=0;i<4;i++){
for(int j=0;j<8;j++){
num+=x[i][j]*(1LL<<(i*8+j));
}
}
return num;
}

node st;
int bfs(){
queue<node> q;
st.step=0;
q.push(st);
insert(encode(st.a));//访问标记

while(!q.empty()){
node tt=q.front();q.pop();
for(int i=0;i<4;i++){//一次扩展四个空格
node s=tt;
int x=s.a[s.x[i]][s.y[i]-1];
if(x%10==7||x==0)continue;
x++;
for(int j=0;j<4;j++)for(int k=0;k<8;k++)if(s.a[j][k]==x){
swap(s.a[j][k],s.a[s.x[i]][s.y[i]]);
LL tmp=encode(s.a);
if(tmp==aimEncode){
return s.step+1;
}
if(!find(tmp)){
insert(tmp);
s.step++;
s.x[i]=j;
s.y[i]=k;
q.push(s);
}
goto A;
}
A:;
}
}
return -1;
}

int main(){

int T;
scanf("%d",&T);
while(T--){
//cl(st.a,0);
for(int i=0;i<mod;i++)hash_[i].clear();
st.a[0][0]=st.a[1][0]=0;
st.a[2][0]=st.a[3][0]=0;
int num=0;
for(int i=0;i<4;i++){
for(int j=1;j<=7;j++){
int x;
scanf("%d",&st.a[i][j]);
x=st.a[i][j];
if(x==11){
swap(st.a[0][0],st.a[i][j]);
st.x[num]=i;st.y[num++]=j;
}
else if(x==21){
swap(st.a[1][0],st.a[i][j]);
st.x[num]=i;st.y[num++]=j;
}
else if(x==31){
swap(st.a[2][0],st.a[i][j]);
st.x[num]=i;st.y[num++]=j;
}
else if(x==41){
swap(st.a[3][0],st.a[i][j]);
st.x[num]=i;st.y[num++]=j;
}
}
}///end of for

if(encode(st.a)==aimEncode){
puts("0");continue;
}
printf("%d\n",bfs());

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: