• IDAstar搜索


    http://poj.org/problem?id=1077
    
    Source Code
    
    Problem: 1077  User: p_hoenix 
    Memory: 220K  Time: 0MS 
    Language: C++  Result: Accepted 
    
    Source Code 
    #include <iostream>
    #include <utility>
    #include <vector>
    #include <fstream>
    #include <math.h>
    using namespace std;
    
    const int MAX = 1 << 20;
    const int ROW = 3, COL = 3;
    
    
    
    //棋盘
    struct Board
    {
    	Board& operator=(const Board &b)
    	{
    		for(int i = 0; i < ROW; i++)
    			for(int j = 0; j < COL; j++)
    				tile[i][j] = b.tile[i][j];
    		r = b.r;
    		c = b.c;
    		return *this;
    	}
    	int tile[ROW][COL];//4*4的方块
    	int r,c;//空格的位置
    };
    typedef Board Status;
    
    struct Step
    {
    	int r,c;
    	int dir;
    };
    
    class PicturePizzle
    {
    public:
    	friend void input(PicturePizzle &pp);
    	
    	PicturePizzle()
    	{
    		pStepDir = (int*)malloc(sizeof(int) * MAX);
    		stepHeap = (Board*)malloc(sizeof(Board) * MAX);
    	}
    	
    	~PicturePizzle()
    	{
    		free(pStepDir);
    		free(stepHeap);
    	}
    	//移动步骤.
    	typedef struct{
    		int r,c;//空格位置
    		int dir;//移动方向
    	}Step;
    	
    	//判断以该状态开始是否可以完成拼图
    	bool JudgeValidStatus();
    	//heuristic function,启发式函数,计算(估算)最大移动步数
    	int Heuristic();
    	//IDA*搜索寻找移动方案
    	//当前状态,深度,h(),前一步的移动方向.
    	bool IDAstar(Status &s, int depth, int h, int prevDir);
    	
    	//打印移动路径
    	void ShowStep(int depth);
    	
    	void Run();
    	
    	//private:
    	Board board;
    	int h;
    	int maxDepth;
    	vector<Board> step;
    	int *pStepDir;
    	Board *stepHeap;
    	//郁闷的地方,C++ primer里面说可以给const static在里面初始化,在类外面定义的,但是VC6.0不可以
    	//目标棋盘
    	const static Board destBoard;// = {1 ,2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 4, 4};
    	const static int nDestPos[ROW * COL + 1][2];//最终棋盘的各个方块的位置
    	const static int dir[4][2];
    };
    
    //1到16的方块编号
    const Board PicturePizzle::destBoard = {1 ,2, 3, 4, 5, 6, 7, 8, 9, 2, 2};//10, 11, 12, 13, 14, 15, 16, 3, 3};
    const int PicturePizzle::nDestPos[ROW * COL + 1][2] = {{-1, -1},
    {0, 0}, {0, 1}, {0, 2},
    {1, 0}, {1, 1},{1, 2},
    {2, 0}, {2, 1}, {2, 2}};
    //{3, 0}, {3, 1}, {3, 2}, {3, 3}};
    
    const int PicturePizzle::dir[4][2] = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};//左上右下
    
    bool PicturePizzle::JudgeValidStatus()
    {
    	int i, j, array[ROW * COL], k, sum;
    	sum = k = 0;
    	//转化成一维数组
    	for(i = 0; i < ROW; i++)
    		for(j = 0; j < COL; j++)
    		{
    			array[k++] = board.tile[i][j];
    		}
    	//因为在最终状态下,棋盘的一维数组是有序递增的.
    	//除了X结点外,要到达目标位置需要移动的最大步数,因为在转换成了一维后原本可以上下移动的都被转化成了水平移动.
    	//但是幸运的是,他们是同奇同偶的.具体的证明我也不知道,画图有这么个规律
    	for(i = 0; i <= ROW * COL - 2; i++)
    		for(j = i + 1; j <= ROW * COL - 1; j++)
    			if(array[i] > array[j])
    				sum++;
    	//这个是X方块到目标位置的最短步数,不管怎么移动,只要最后是在目标位置,必定是同奇同偶的.(简单的考虑就是撤销)
    	//而每一次的其他方块的移动都是与X方块的交换来实现的,所以他们的和必定是偶数
    	sum += abs(board.r - nDestPos[ROW * COL][0]) + abs(board.c - nDestPos[ROW * COL][1]);
    	return sum % 2 == 0;
    }
    
    int PicturePizzle::Heuristic()
    {
    	int r, c, tile, sum = 0;
    	for(r = 0; r < ROW; r++)
    		for(c = 0; c < COL; c++)
    		{
    			tile = board.tile[r][c];
    			//计算每个方块(非空格)移动到目标位置的曼哈顿距离,不需要计算空格
    			if(tile != ROW * COL)
    			{
    				sum += abs(r - nDestPos[tile][0]) + abs(c - nDestPos[tile][1]);
    			}
    		}
    	h = sum;
    	return sum;
    }
    
    
    
    int global = 0;
    bool PicturePizzle::IDAstar(Status &s, int depth, int h, int prevDir)
    {
    	//cout<<global++<<endl;
    	
    	if(memcmp(&s, &destBoard, sizeof(destBoard)) == 0)//到达目标状态
    	{
    		this->ShowStep(depth);
    		return true;
    	}
    	if(depth >= maxDepth)//超过当前深度
    		return false;
    	Status ns;
    	int nr,nc,nh,moveTile;
    	for(int d = 0; d < 4; d++)
    	{
    		if(abs(d - prevDir) == 2)//会撤销上次的移动
    			continue;
    		ns = s;
    		nr = s.r + dir[d][0];
    		nc = s.c + dir[d][1];
    		if(nr < 0 || nr > ROW - 1 || nc < 0 || nc > COL - 1)//越界
    			continue;
    		//移动方块
    		moveTile = s.tile[nr][nc];
    		ns.tile[s.r][s.c] = moveTile;
    		ns.tile[nr][nc] = ROW * COL;
    		ns.r = nr;
    		ns.c = nc;
    		
    		//向左移动.并且与X交换的方块离它的目标位置近了一步.
    		//反过来,因为X是向左的,那么moveTile就是向右的,那么这个时候只有moveTile在它的目标位置的左边的时候才成立
    		//也就是说它原来的位置nc是在目标的左边
    		if(d == 0 && nc < nDestPos[moveTile][1])
    			nh = h - 1;//nh比当前的h少1
    		else if(d == 1 && nr < nDestPos[moveTile][0])//上
    			nh = h - 1;
    		else if(d == 2 && nc > nDestPos[moveTile][1])//右
    			nh = h - 1;
    		else if(d == 3 && nr > nDestPos[moveTile][0])
    			nh = h - 1;
    		else
    			nh = h + 1;
    		
    		//大于f
    		if(depth + nh > maxDepth)
    			continue;
    		
    		//step.insert(step.begin() + depth, ns);
    		//step.erase(step.begin() + depth + 1);
    		
    		pStepDir[depth] = d;
    		stepHeap[depth] = ns;
    		
    		if(IDAstar(ns, depth + 1, nh, d))
    			return true;
    	}
    	return false;
    }
    
    
    void PicturePizzle::ShowStep(int depth)
    {
    	int i = 0;
    	//cout<<depth<<endl;
    	
    	for(i = 0; i < depth; i++)
    		switch(pStepDir[i])
    	{
    		case 0:
    			cout<<'l';
    			break;
    		case 1:
    			cout<<'u';
    			break;
    		case 2:
    			cout<<'r';
    			break;
    		case 3:
    			cout<<'d';
    			break;
    	}
    	cout<<endl;
    	/*
    	for(i = 0; i < depth; i++)
    	{
    	for(int r = 0; r < ROW; r++)
    	{
    	for(int c = 0; c < COL; c++)
    	cout<<stepHeap[i].tile[r][c]<<"\t";
    	cout<<endl;
    	}
    	cout<<endl<<endl;
    	}
    	*/
    	
    	/*
    	cout<<step.size()<<endl<<endl;
    	for(vector<Board>::iterator iter = step.begin(); iter != step.end(); iter++)
    	{
    	cout<<i++<<endl;
    	for(int r = 0; r < 4; r++)
    	{
    	for(int c = 0; c < 4; c++)
    				cout<<iter->tile[r][c]<<"\t";
    				cout<<endl;
    				}
    				cout<<endl<<endl;
    }*/
    }
    
    void PicturePizzle::Run()
    {
    	if(JudgeValidStatus())
    	{
    		maxDepth = Heuristic();
    		while(maxDepth++)
    			if(IDAstar(board, 0, h, 20))
    				break;
    	}
    	else
    	{
    		cout<<"unsolvable"<<endl;
    	}
    	
    }
    
    void input(PicturePizzle &pp)
    {
    	//cout<<"输入一个文件(.txt),表示拼图的初始"
    	//fstream file("in.txt");
    	int num;
    	for(int r = 0; r < ROW; r++)
    		for(int c = 0; c < COL; c++)
    		{
    			//file>>num;
    			cin>>num;
    			if(/*file.fail()*/cin.fail())
    			{
    				//file.clear();
    				//file.ignore(1,'\t');
    				cin.clear();
    				cin.ignore(1, ' ');
    				pp.board.tile[r][c] = ROW * COL;
    				pp.board.r = r;
    				pp.board.c = c;
    			}
    			else
    				pp.board.tile[r][c] = num;
    		}
    		//file.close();
    }
    
    
    
    int main()
    {
    	//freopen("out.txt", "w", stdout);
    	
    	PicturePizzle pp;
    	input(pp);
    	pp.Run();
    	
    	return 0;
    }
    
    
  • 相关阅读:
    C++考试篇二:继承与派生
    当初的愿望实现了么?
    Ckeditor 的使用
    2012 年取公积金
    CodeWarrior下载程序到9S12XS128
    [置顶] CentOS6.3三种安装方法(U盘,硬盘,光盘)
    重大改变!DotMSN于今天开放了源代码,并升级到2.0版本!!
    创建跨平台的Ajax应用
    创建跨平台的Ajax应用
    C#编写最小花时隐藏为任务栏图标的Window appllication
  • 原文地址:https://www.cnblogs.com/steady/p/1936901.html
Copyright © 2020-2023  润新知