zoukankan      html  css  js  c++  java
  • 题解——八数码难题

    思路

    由明确的两种状态可以想到

    D(double)BFS即双向BFS

    输入的是个

    283104765
    

    然而 凡是搜索都有个标记即vis[]

    但 按题意3 * 3的地图不好标记(也许用map可以)

    于是直接用一维dir数组改成

    int dir[4] = {1,-3,-1,3};
    

    但九位数也是开不了的

    就有一个cantor展开式

    状态压缩一下

    inline int cantor(int a[])
    {
    	int i,j,ans = 0;
    	for(i = 0;i < 9;i++)
    	{
    		int s = 0;
    		for(j = i + 1;j < 9;j++)
    			if(a[j] < a[i]) s++;
    		ans += s * fac[8 - i];
    	}
    	return ans;
    }
    

    然后就行了 DBFS直接套板子啊

    优化

    其实就上面的好像就可以过了

    但还有个优化

    逆序对有关

    将3 * 3 的图 弄成序列

    可以得出结论:初始状态的逆序对模2必须等于目标状态的逆序对模2,否则无法达成,输出-1

    证明

    可以转为 初始状态无论如何改变其奇偶性不变

    位置图

    1 2 3

    4 5 6

    7 8 9

    将3 * 3 的图 弄成序列

    1 2 3 4 5 6 7 8 9

    注意 0 不算入队列 所以上面实际上是8个

    ~~

    2 8 3

    1 0 4

    7 6 5

    可见 当位置5的0与位置8的6交换会有几种情况

    位置n的数 为方便简写为(n)

    Case1:(6)和(7)中有0个比(8)小

    则逆序对+ 2

    Case2:(6)和(7)中有1个比(8)小

    则逆序对- 1 + 1

    Case2:(6)和(7)中有2个比(8)小

    则逆序对+ 2

    综上逆序对奇偶性不变

    其它交换情况可以类似讨论

    代码

    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    using namespace std;
    const int MAXN = 400000;
    int step[2][MAXN],fac[10] = {1,1,2,6,24,120,720,5040,40320,362880};
    bool vis[2][MAXN];
    int dir[4] = {1,-3,-1,3};
    
    //cantor状态压缩
    inline int cantor(int a[])
    {
    	int i,j,ans = 0;
    	for(i = 0;i < 9;i++)
    	{
    		int s = 0;
    		for(j = i + 1;j < 9;j++)
    			if(a[j] < a[i]) s++;
    		ans += s * fac[8 - i];
    	}
    	return ans;
    }
    struct Node
    {
    	int word[9],loc,ca;
    	bool f;
    	void node(int Word[],int LOC,int CA,bool F)
    	{
    		for(int i = 0;i < 9;i++) word[i] = Word[i];
    		loc = LOC,ca = CA,f = F;
    	}
    }Start,order;
    inline int dbfs()
    {
    	queue<Node> q;
    	Start.f = 1,order.f = 0;
    	q.push(Start);
    	q.push(order);
    	int i;
    	while(!q.empty())
    	{
    		Node tmp = q.front();
    		q.pop();
    		if(vis[!tmp.f][tmp.ca])
    			return (step[1][tmp.ca] + step[0][tmp.ca]);
    		int Step = step[tmp.f][tmp.ca];
    		for(i = 0;i < 4;i++)
    		{
    			int poss = tmp.loc + dir[i];
                
                //由于dir数组改了 判断也得改
    			if(0 <= poss&&poss < 9&&(tmp.loc % 3 == poss % 3||tmp.loc / 3 == poss / 3))
    			{
    				swap(tmp.word[tmp.loc],tmp.word[poss]);
    				int nca = cantor(tmp.word);
    				if(!vis[tmp.f][nca])
    				{
    					Node g;
    					vis[tmp.f][nca] = 1;
    					step[tmp.f][nca] = Step + 1;
    					g.node(tmp.word,poss,nca,tmp.f);
    					q.push(g);
    				}
    				swap(tmp.word[tmp.loc],tmp.word[poss]);	
    			}
    		}
    	}
    	return -1;
    }
    
    //优化 求逆序对
    inline int cutdown(int a[])
    {
    	int i,j,q = 0;
    	for(i = 0;i < 9;i++)
    		for(j = i + 1;j < 9;j++)
    			if(a[i] != 0&&a[j] != 0&&a[j] < a[i]) q++;
    	return q;
    }
    int main()
    {
    	int i;
    	for(i = 0;i < 9;i++) 
    	{
    		scanf("%d",&Start.word[i]);
    		if(!Start.word[i]) Start.loc = i;
    	}
    	for(i = 0;i < 9;i++)
    	{
    		scanf("%d",&order.word[i]);
    		if(!order.word[i]) order.loc = i;
    	}
        //优化
    	if(cutdown(Start.word) % 2 != cutdown(order.word) % 2)
    	{
    		printf("-1");
    		return 0;
    	}
    	Start.ca = cantor(Start.word);
    	vis[1][Start.ca] = 1;
    	order.ca = cantor(order.word);
    	vis[0][order.ca] = 1;
    	printf("%d",dbfs());
    	return 0;
    }
    
  • 相关阅读:
    myeclipse的git插件安装
    安装虚拟机和Linux系统
    Windows 10快速在指定目录打开命令行
    更新Maven的本地库
    Maven安装
    html全屏显示
    除法保留两位小数
    springmvcjson中文乱码处理
    office2016 下载直通车
    JAVA面向对象编程深入理解图
  • 原文地址:https://www.cnblogs.com/resftlmuttmotw/p/11323219.html
Copyright © 2011-2022 走看看