码迷,mamicode.com
首页 > 编程语言 > 详细

【启发式搜索】【A*算法】hdu6171 Admiral

时间:2017-08-24 22:40:00      阅读:412      评论:0      收藏:0      [点我收藏+]

标签:目标   too   class   turn   images   pair   set   hdu   int   

技术分享

一个舰队的目标状态如上图。红色是旗舰。然后给你初始局面,每一次决策可以把旗舰和其上一层或下一层的两个相邻的进行交换。如果能在20步内出解的话,输出最小步数;否则输出“too difficult”。

把每个方块当成0~5的数,整个状态正好可以压缩成1个21位的6进制数,恰好可以用long long存下,可以用set / 哈希表存储。

定义估价函数f(S)表示局面S的每个格子所在层数与它的目标状态所在层的差的绝对值之和。

这样每一次移动最多使这个值减小2,如果这个值大于(20-已经走的步数)*2,则剪枝。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
const int dx[]={1,1,-1,-1},dy[]={0,1,0,-1};
typedef long long ll;
typedef pair<int,int> Point;
set<ll>S;
int T;
struct Node{
	ll st;
	Point pos;
	int d;
	Node(){}
	Node(const ll &st,const Point &pos,const int &d){
		this->st=st;
		this->pos=pos;
		this->d=d;
	}
};
int ceng[25];
int Abs(int x){
	return x<0 ? (-x) : x;
}
int calc(ll x){
	int res=0;
	for(int i=0;i<=20;++i){
		res+=Abs((int)(x%6ll)-ceng[i]);
		x/=6;
	}
	return res;
}
queue<Node>q;
int wei[8][8];
ll pw[30];
int main(){
	int x;
//	freopen("1001.in","r",stdin);
//	freopen("1001.out","w",stdout);
	pw[0]=1;
	for(int i=1;i<=20;++i){
		pw[i]=pw[i-1]*6ll;
	}
	scanf("%d",&T);
	ceng[0]=ceng[1]=ceng[2]=ceng[3]=ceng[4]=ceng[5]=5;
	ceng[6]=ceng[7]=ceng[8]=ceng[9]=ceng[10]=4;
	ceng[11]=ceng[12]=ceng[13]=ceng[14]=3;
	ceng[15]=ceng[16]=ceng[17]=2;
	ceng[18]=ceng[19]=1;
	ceng[20]=0;
	int pen=20;
	for(int i=0;i<6;++i){
		for(int j=0;j<=i;++j){
			wei[i][j]=pen;
			--pen;
		}
	}
	ll goal=0;
	for(int i=0;i<6;++i){
		for(int j=0;j<=i;++j){
			goal=goal*6ll+(ll)i;
		}
	}
	for(;T;--T){
		S.clear();
		ll st=0;
		Point stapos;
		for(int i=0;i<6;++i){
			for(int j=0;j<=i;++j){
				scanf("%d",&x);
				if(x==0){
					stapos=Point(i,j);
				}
				st=st*6ll+(ll)x;
			}
		}
		if(st==goal){
			puts("0");
			continue;
		}
		S.insert(st);
		bool ok=0;
		while(!q.empty()){
			q.pop();
		}
		q.push(Node(st,stapos,0));
		while(!q.empty()){
			Node U=q.front(); q.pop();
//			ll now=U.st;
//			for(int i=0;i<6;++i){
//				for(int j=0;j<=i;++j){
//					printf("%I64d ",now/pw[wei[i][j]]%6ll);
//				}
//				puts("");
//			}
//			puts("");
			if(U.d>=20){
				continue;
			}
			for(int i=0;i<4;++i){
				int tx=U.pos.first+dx[i],ty=U.pos.second+dy[i];
				if(tx>=0 && tx<=5 && ty>=0 && ty<=tx){
					ll nextst=U.st-pw[wei[tx][ty]]*(U.st/pw[wei[tx][ty]]%6ll);
					nextst+=pw[wei[U.pos.first][U.pos.second]]*(U.st/pw[wei[tx][ty]]%6ll);
					int tmp=calc(nextst);
					if(S.find(nextst)==S.end() && tmp<=(20-(U.d+1))*2){
						if(nextst==goal){
							ok=1;
							printf("%d\n",U.d+1);
							break;
						}
						S.insert(nextst);
						q.push(Node(nextst,Point(tx,ty),U.d+1));
					}
				}
			}
			if(ok){
				break;
			}
		}
		if(!ok){
			puts("too difficult");
		}
	}
	return 0;
}

【启发式搜索】【A*算法】hdu6171 Admiral

标签:目标   too   class   turn   images   pair   set   hdu   int   

原文地址:http://www.cnblogs.com/autsky-jadek/p/7425397.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!