poj 1077 Eight

POJ1077 Eight A* 题目链接 http://poj.org/problem?id=1077 分析 直接用BFS进行状态扩展会超时,需要设计估价函数跑A*算法。 每次只能使一个数位置改变,因此未来的操作次数不会小于每个数当前位置于最终位置的曼哈顿距离之和。 用这个作为估价函数,用康托展开将排列映射成整数来记录某一状态是否访问过。 有一结论,如果列数为奇数,那么初始状态和最终状态的逆序对数奇偶性相同。 AC代码 // 调... 阅读详情

 

Eight
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 9915 Accepted: 4303 Special Judge

Description

The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
 1  2  3  4 

 5  6  7  8 

 9 10 11 12 

13 14 15  x 

where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
 1  2  3  4    1  2  3  4    1  2  3  4    1  2  3  4 

 5  6  7  8    5  6  7  8    5  6  7  8    5  6  7  8 

 9  x 10 12    9 10  x 12    9 10 11 12    9 10 11 12 

13 14 11 15   13 14 11 15   13 14  x 15   13 14 15  x 

           r->           d->           r-> 

The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.

Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).

In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.

Input

You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
 1  2  3 

 x  4  6 

 7  5  8 

is described by this list:
 1 2 3 x 4 6 7 5 8 

Output

You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.

Sample Input

 2  3  4  1  5  x  7  6  8 

Sample Output

ullddrurdllurdruldr

Source


/*好久没有遇到这么大快人心的题了,虽然做了一天多,但是这次一改以往遇到陌生题比较浮躁的态度,认真去学习了相关知识。
通过这道题学习了A*算法,以及排列数一种常见的hash算法,并实际使用和操作了最大堆,可以说是收获颇多
*/
/*注意程序中的两个优化:
如果两个优化都没有,则会TLE
如果只用优化2,而不用优化1,所用时间为,同样会TLE
如果只用优化1,而不用优化2,所用时间为:
5782538	bobten2008	1077	Accepted	8752K	47MS	C++	7345B	2009-08-30 14:52:15
如果两个都用,则时间为:
5782475	bobten2008	1077	Accepted	9128K	16MS	C++	7329B	2009-08-30 14:41:28
所以可见优化二的作用是决定性的
*/
#include <iostream>
#define MAX_N 362880 //利用阶乘逆序数来计算Hash值,最大hash值是9! - 1
using namespace std;
//0-9的阶乘,用来计算哈希值
int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
int temp[10];
//记录1 - 9 九个位置可以移动的方向的个数
int dirN[10] = {0, 2, 3, 2, 3, 4, 3, 2, 3, 2};
//记录1 - 9 九个位置可以移动的方向的种类
char dirT[10][6] =  {
{' '},
{' ', 'r', 'd'},
{' ', 'l', 'r', 'd'},
{' ', 'l', 'd'},
{' ', 'u', 'r', 'd'},
{' ', 'u', 'l', 'r', 'd'},
{' ', 'u', 'l', 'd'},
{' ', 'u', 'r'},
{' ', 'u', 'l', 'r'},
{' ', 'u', 'l'}};
int heap[MAX_N + 5];
int heapSize = 0;
int initState, finalState = 123456789, curPos;
struct node
{
    int type;   //0 尚未访问, 1 已经在待考察队列中 2 被访问过并从待访问队列中删除了
	int heapPos; //当前状态在堆中的位置
    int state;  //当前状态,如123456789
    char dType; //上一个状态到当前状态所走的方向
    int diff;   //A*算法中的h()用当前状态和终止状态之间的different * 10 表示(不计空格)
    int step;   //A*算法中的g(),表示当前遍历的深度
    int fVal;   //diff和step的和,堆算法主要基于这个指标
    node()
    {
        step = 0;
        type = 0;
    }
}hashT[MAX_N + 5]; //哈希表
int eP(int l)  //计算10的l次方
{
    int res = 1;
    for(int i = 1; i <= l; i++)
        res *= 10;
    return res;
}
int getNum(int which, int num) //通过当前状态取3 × 3方格中的第which个数
{
    if(which > num % 10)
        return num / eP(9 - which + 1) % 10;
    else
        return num / eP(9 - which) % 10;
}
//以下均是移动空格的位置
int moveL(int state) //由当前状态左移得到新的状态
{
    return state - 1;
}
int moveR(int state) //由当前状态右移得到新的状态
{
    return state + 1;
}
int moveU(int state) //由当前状态下移得到新的状态
{
    int t0 = 9 - state % 10 + 1;
    int t1 = state / eP(t0);
    int t2 = t1 % 1000;
    t1 = t1 - t2 + (t2 % 100) * 10 + t2 / 100;
    t1 = t1 * eP(t0);
    return t1 + state % eP(t0) - 3;
}
int moveD(int state) //由当前状态上移得到新的状态
{
    int t0 = 7 - state % 10;
    int t1 = state / eP(t0);
    int t2 = t1 % 1000;
    t1 = t1 - t2 + (t2 % 10) * 100 + t2 / 10;
    t1 = t1 * eP(t0);
    return t1 + state % eP(t0) + 3;
}
int getRevNum(int state) //得到当前状态的逆序数,最后一位表示空格,不计
{
    int blank = state % 10;
    int total = 0;
    int p = 0;
    for(int id = 1; id <= 9; id++)
    {
        if(id == blank)
            continue;
        int n = getNum(id, state);
        temp[p++] = n;
        for(int k = p - 2; k >= 0; k--)
            if(temp[k] >= n)
                total++;
    }
    return total;
}
//通过当前状态得到其对应的哈希值
//这里计算哈希值采用1-9每位的逆序数乘以(位数减一的阶乘)并取和的方法,这样
//可以保证最大的哈希值为9! - 1且没个状态的哈希值都唯一
int getHashNum(int state) 
{
    int blank = state % 10;
    int hashVal = 0;
    int p = 0, total;
    int pp = 0; //pp记录阶乘的位置
    for(int id = 1; id <= 9; id++)
    {
        pp++;
        if(id == blank)
            continue;
        int n = getNum(id, state);
        temp[p++] = n;
        total = 0;
        for(int k = p - 2; k >= 0; k--)
        {
            if(temp[k] >= n)
                total++;
        }
        hashVal += total * fac[p - 1];
    }
    // 空格作为最小值计算
    return hashVal + (blank - 1) * fac[blank - 1];

}
//计算两个状态的距离
int getDiff(int state1, int state2)
{
    int blank1 = state1 % 10, blank2 = state2 % 10, i, diff = 0;
	if(blank1 != blank2) diff += 2;
    for(i = 1; i <= 9; i++)
    {
        if(i != blank1 && i != blank2 && getNum(i, state1) != getNum(i, state2))
			diff++;
    }
    return diff;
}
void swapHeapV(int i, int j)
{
    int temp = heap[i];
    heap[i] = heap[j];
    heap[j] = temp;
	hashT[heap[i]].heapPos = i;
	hashT[heap[j]].heapPos = j;
}
//从i结点保证堆的性质
void maxHeapify(int i)
{
    int l = 2 * i, r = 2 * i + 1, largest;
    if(l <= heapSize && hashT[heap[l]].fVal < hashT[heap[i]].fVal)
        largest = l;
    else
        largest = i;
    if(r <= heapSize && hashT[heap[r]].fVal < hashT[heap[largest]].fVal)
        largest = r;
    
    if(largest != i)
    {
        swapHeapV(i, largest);
        maxHeapify(largest);
    }
}
//取堆中的最大值
int getHeapMax()
{
    return heap[1];    
}
//取堆中的最大值,并删除这个值,需要用maxHeapify(1)来保持最大堆的性质
int extracMaxHeap()
{
    if(heapSize < 1)
        return -1;
    int maxv = heap[1];
    heap[1] = heap[heapSize];
	hashT[heap[1]].heapPos = 1;
    heapSize--;
    maxHeapify(1);
    return maxv;
}
//向对中插入结点i
void heapInsert(int i)
{
    heapSize++;
    heap[heapSize] = i;
	hashT[i].heapPos = heapSize;
    int pos = heapSize;
    while(pos > 1 && hashT[heap[int(pos / 2)]].fVal > hashT[heap[pos]].fVal)
    {
        swapHeapV(pos, int(pos / 2));
        pos = pos / 2;
    }
}
//当结点i的权值发生变化时,需要更新堆的结构以保证最大堆的性质
void upMoveHeap(int i)
{
    int pos = i;
    while(pos > 1 && hashT[heap[int(pos / 2)]].fVal > hashT[heap[pos]].fVal)
    {
        swapHeapV(pos, int(pos / 2));
        pos = pos / 2;
    }
}
//递归打印结果
void printRes(int curState)
{
    int hashVal = getHashNum(curState);
    char dType = hashT[hashVal].dType;
    if(dType != 's')
    {
        
        if(dType == 'l')
        {
            printRes(moveR(curState));
            cout<<'l';
        }
        else if(dType == 'r')
        {
            printRes(moveL(curState));
            cout<<'r';
        }
        else if(dType == 'u')
        {
            printRes(moveD(curState));
            cout<<'u';
        }
        else if(dType == 'd')
        {
            printRes(moveU(curState));
            cout<<'d';
        }
    }
}
//计算的核心控制函数
void getBest()
{
    //计算并初始化初始结点的相关性质
    int h = getHashNum(initState), d, curHashVal, curState, xPos, nextState, nextHashVal, nextHeapPos;
    char type;
    hashT[h].state = initState;
    hashT[h].type = 1;
    hashT[h].dType = 's';
    hashT[h].step = 0;
	//将初始节点插入堆中
    heapInsert(h);
    while(true)
    {
        //取当前堆中最大的结点
        curHashVal = extracMaxHeap();
        //设置当前状态为从待考察队列中删除
        hashT[curHashVal].type = 2;
        
        curState = hashT[curHashVal].state;
        
        //到达终止结点
        if(curState == finalState)
        {
            printRes(curState);
            cout<<endl;
            break;
        }
        xPos = curState % 10;
        
        //遍历空格可以走的方向
        for(d = 1; d <= dirN[xPos]; d++)
        {
            type = dirT[xPos][d];
            if(type == 'r')
            {
                //从当前节点向右走到达新的状态
                nextState = moveR(curState);
                //计算新状态的哈希值
                nextHashVal = getHashNum(nextState);
				nextHeapPos = hashT[nextHashVal].heapPos;
                //如果此状态已经被访问过
                if(hashT[nextHashVal].type != 0)
                {
                    //优化1:更新此状态的g函数,即遍历的深度
                    if(hashT[curHashVal].step + 1 < hashT[nextHashVal].step)
                    {
                        hashT[nextHashVal].step = hashT[curHashVal].step + 1;
                        hashT[nextHashVal].fVal = hashT[nextHashVal].step + hashT[nextHashVal].diff;
                        //更新堆的结构以保证最大堆的性质
                        upMoveHeap(nextHeapPos);
                    }
                    continue;
                }
                //记录方向
                hashT[nextHashVal].dType = 'r';
            }
            else if(type == 'l')
            {
                nextState = moveL(curState);
                nextHashVal = getHashNum(nextState);
				nextHeapPos = hashT[nextHashVal].heapPos;
                if(hashT[nextHashVal].type != 0)
                {
                    if(hashT[curHashVal].step + 1 < hashT[nextHashVal].step)
                    {
                        hashT[nextHashVal].step = hashT[curHashVal].step + 1;
                        hashT[nextHashVal].fVal = hashT[nextHashVal].step + hashT[nextHashVal].diff;
                        upMoveHeap(nextHeapPos);
                    }
                    continue;
                }
                hashT[nextHashVal].dType = 'l';
            }
            else if(type == 'u')
            {
                nextState = moveU(curState);
                nextHashVal = getHashNum(nextState);
				nextHeapPos = hashT[nextHashVal].heapPos;
                if(hashT[nextHashVal].type != 0)
                {
                    if(hashT[curHashVal].step + 1 < hashT[nextHashVal].step)
                    {
                        hashT[nextHashVal].step = hashT[curHashVal].step + 1;
                        hashT[nextHashVal].fVal = hashT[nextHashVal].step + hashT[nextHashVal].diff;
                        upMoveHeap(nextHeapPos);
                    }
                    continue;
                }
                hashT[nextHashVal].dType = 'u';
            }
            else if(type == 'd')
            {
                nextState = moveD(curState);
                nextHashVal = getHashNum(nextState);
				nextHeapPos = hashT[nextHashVal].heapPos;
                if(hashT[nextHashVal].type != 0)
                {
                    if(hashT[curHashVal].step + 1 < hashT[nextHashVal].step)
                    {
                        hashT[nextHashVal].step = hashT[curHashVal].step + 1;
                        hashT[nextHashVal].fVal = hashT[nextHashVal].step + hashT[nextHashVal].diff;
                        upMoveHeap(nextHeapPos);
                    }
                    continue;
                }
                hashT[nextHashVal].dType = 'd';
            }
            
            //存储并计算新状态的相关信息
            hashT[nextHashVal].state = nextState;
            //g函数:遍历的深度加一
            hashT[nextHashVal].step = hashT[curHashVal].step + 1;
            //h函数:优化2,将h函数乘以10可以降低深度的影响,从而提高A*算法的效率,但是结果一般不是最优的了
            hashT[nextHashVal].diff = getDiff(nextState, finalState) * 10;
            //计算:f函数即g函数和h函数之和
            hashT[nextHashVal].fVal = hashT[nextHashVal].diff + hashT[nextHashVal].step;
            //标记此状态已经加入待考察队列
            hashT[nextHashVal].type = 1;
            //将新状态加入堆(待考察队列)
            heapInsert(nextHashVal);
        }
    }
}
int main()
{
    
    char ch;
    int i;
    initState = 0;
    for(i = 1; i <= 9; i++)
    {
        cin>>ch;
        if(ch == 'x')
            curPos = i;
        else
            initState = initState * 10 + int(ch - '0');
    }
    initState = initState * 10 + curPos;
    int revInit = getRevNum(initState);
    if(revInit % 2 != 0)
        cout<<"unsolvable"<<endl;
    else if(initState == finalState)
        cout<<"lr"<<endl;
    else
        getBest();
 
 return 0;
}


POJ1077 Eight —— 正向BFS 主页面:http://write.blog.youkuaiyun.com/postedit/77825569 代码一:以数组充当队列,利用结构体中的pre追溯上一个状态在数组(队列)中的下标: #include #include #include #include #include #include #include #include #include #in 阅读详情

相关推荐

POJ1077 Eight —— 反向BFS

主页面:http://write.blog.youkuaiyun.com/postedit/77825569 代码一:以数组充当队列,利用结构体中的pre追溯上一个状态在数组(队列)中的下标: #include #include #include #include #include #include #include #include #include #incl

A man can be destroyed, but not defeated. 862

POJ 1077 Eight(BFS:输出路径)

POJ 1077 Eight(BFS:输出路径) http://poj.org/problem?id=1077 题意:给你一个八数码3*3的网格,要你输出解的路径. 分析:参考刘汝佳入门经典P132.        首先对于每个网格状态,我们把它转化为一个9位的十进制数.然后用state[][9]二维数组来保存所有的我们已经发现的状态st,且用state[]来表示当前我们用的栈.

code 1467

深入解析DDR5 RFM机制:从JESD79-5标准到硬件实现

本文深入解析了DDR5内存标准中的关键机制——RFM(Refresh Management)。文章从JESD79-5标准出发,详细阐述了RFM如何通过RAA计数器实现从被动定时到主动响应的智能刷新管理,并探讨了其硬件实现细节、命令调度挑战及系统级设计考量,为芯片设计工程师优化DDR5内存子系统性能与可靠性提供了实践指导。

fff88的博客 491

POJ - 1077 Eight(A∗算法)

POJ - 1077 Eight(A∗算法) #include<iostream> #include<algorithm> #include<map> #include<queue> #define x first #define y second using namespace std; typedef pair<int,string> PIS; typedef pair<char,string> PCS; int f(

00后的博客 515

ROS 入门教程:小乌龟仿真器和基础操作

小乌龟仿真器和ros基础操作

zlflll的博客 4126

实战教程:如何用Python+小波变换+CNN搞定医学影像中的条纹噪声(附完整代码)

本文提供了一套完整的实战方案,指导如何利用Python结合小波变换与卷积神经网络(CNN)去除医学影像中的条纹噪声。该方法通过小波变换精准定位噪声,再使用轻量化CNN进行针对性清除,有效保护图像细节,并附有可运行的完整代码,为医学影像处理与AI分析提供高效工具。

weixin_29056101的博客 269

poj1077Eight

Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 21880   Accepted: 9674   Special Judge Description The 15-puzzle has been around for over 100 years;

Min_lala的专栏 1035

第1章第11节:创建可容纳多行滚动文字的输入框TextEditor [SwiftUI快速入门到实战]

TextField可以让用户输入单行的文字内容,若想输入多行的文字内容,可以使用能够容纳多行滚动文字的 TextEditor。 定义一个字符串属性,用来存储用户输入的文字内容。接着定义一个布尔属性,用来标识是否弹出警告窗口,以显示用户输入的内容。 TextEditor是由UIKit中的UITextView演变而来,因此可以在init方法中,通过UITextView修改TextEditor的外观属性。 添加一个VStack视图,作为子视图的容器。 创建一个TextEditor,Te..

互动教程网[www.hdjc8.com] 832

POJ 1077 Eight

题目大意: A*:

源代码 924

三模冗余、纠错编码、单粒子翻转防护

本文探讨了高可靠性FPGA系统设计的三大关键技术:三模冗余(TMR)、纠错编码(ECC)和单粒子翻转(SEU)防护。TMR通过三个并行模块和表决器实现容错,但会增加硬件资源和功耗;ECC利用汉明码等编码方式检测和纠正数据错误,适用于存储器保护;SEU防护则针对高能粒子引发的位翻转问题,采用配置刷新、TMR和ECC等方法。文章还通过Verilog代码示例展示了这些技术的实现,并提出了一个综合应用案例,结合三种技术构建高可靠性控制系统。这些技术在航空航天、医疗设备等关键领域具有重要应用价值。

2301_79143213的博客 715

python中有趣的库 freegames 的详细使用

freegames 是一个包含多个简单 Python 游戏的开源库,适合初学者学习 Python 编程和游戏开发。以下是 freegames 的详细介绍和用法示例。

数据知道的博客 3万+

POJ1077Eight

康托逆展开写错还AC的渣渣...

H992109898的博客 788

流体动力学仿真软件:Star-CCM+_(1).Star-CCM+基础及入门

Star-CCM+的用户界面(UI)分为多个部分,包括菜单栏、工具栏、工作区、视图窗口和控制台。菜单栏包含文件、编辑、视图、工具等常用菜单。例如,“File”菜单可以用于打开、保存和退出项目。工具栏提供常用的工具按钮,如新建项目、打开项目、保存项目等。也可以自定义工具栏,添加常用的功能按钮。工作区显示当前项目的结构和各个对象。可以通过拖拽方式组织和管理项目中的各个部分。视图窗口显示几何模型、网格、结果等。可以通过不同的视图模式查看和分析数据。控制台显示软件的运行日志和输出信息。

kkchenjj的博客 1202

POJ1077 Eight —— 经典的搜索问题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 25408    Accepted Submiss

A man can be destroyed, but not defeated. 3460

24、水下传感器网络中混合LEACH协议与遗传算法获取路由节点

本文提出了一种结合遗传算法与LEACH协议的混合路由方案,用于提升水下无线传感器网络(UWSN)的能量利用效率和数据传输稳定性。通过遗传算法优化簇头选择与路径规划,有效避免节点过早死亡,减少能量消耗,在200个节点场景下显著提升网络寿命。相比传统LEACH协议,该方案具有更高的能量利用率、更强的环境适应性,并支持传输历史记录与并行传输序列。实验结果显示,该方案在总能量为2000焦耳时剩余能量达75.6%,远优于LEACH的34.8%能耗表现。适用于海洋监测、石油平台监控及水下灾害预警等复杂环境应用。

i8j9k0l1的博客 112

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

poj1077 /hdoj 1043 Eight

这道题用启发式搜索,我在北大网站上可以过,杭电网站上超时,看来杭电的数据有点变态了。 #include #include #include #include using namespace std; int target_pos[10][2]; char buf[100]; struct state { int pos_i, pos_j; unsigned char m[4

皓首不倦 不负少年 882

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

POJ 1077 Eight A*算法求解

题目描述         在一个3×3的网格中,1~8这8个数字和一个“X”恰好不重不漏地分布在这3×3的网格中。 在游戏过程中,可以把“X”与其上、下、左、右四个方向之一的数字交换(如果存在)。 我们的目的是通过交换,使得网格变为如下排列(称为正确排列): 例如,示例中图形就可以通过让“X”先后与右、下、右三个方向的数字交...

正月看雪花的博客 3562

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

上一篇: POJ 1085 Triangle War
下一篇: POJ 1078
bobten2008
博客等级 码龄18年 153粉丝 157原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值