UESTC 485 Game(康托,BFS)

Today I want to introduce an interesting game to you. Like eight puzzle, it is a square board with 9 positions,
but it filled by 9 numbered
tiles. There is only one type of valid move, which is to rotate one row or column. That is, three tiles in a row or column are moved towards the head by one tile and the head tile is moved to the end of the row or column. So it has 12 different
moves just as the picture left. The objective in the game is to begin with an arbitrary configuration of tiles, and move them so as to get the numbered tiles arranged as the target configuration.

Now the question is to calculate the minimum steps required from the initial configuration to the final configuration. Note that the initial configuration is filled with a permutation of 1 to 9,
but the final configuration is filled with numbers and * (which can be any number).

Input

The first line of input contains an integer T (T≤1000),
which is the number of data sets that follow.

There are 6 lines
in each data set. The first three lines give the initial configuration and the next three lines give the final configuration.

Output

For every test case, you should output Case #k: first, where k indicates
the case number and starts at 1.
Then the fewest steps needed. If he can’t move to the end, just output No Solution! (without quotes).

Sample Input

2

1 2 3

4 5 6

7 8 9

1 2 3

4 5 6

7 9 8

1 2 3

4 5 6

7 8 9

8 * 9

5 3 7

2 * *

Sample Output

Case #1: No Solution!

Case #2: 7

康托展开总结:

http://blog.csdn.net/dacc123/article/details/50952079

利用康托展开

把所有状态bfs一次,

然后再去做

利用康托展开进行bfs预处理。题目给的一个起始的九宫格,和一个目标的九宫格。 不能直接用目标的九宫格去找起始的九宫格,会超时,应该根据把起始九宫格当作

1 2 3

4 5 6

7 8 9

然后确定目标九宫格是怎么样的,这样就可以直接用之前打的表了。预处理就是处理1 2 3 4 5 6 7 8 9到每种九宫格的步数

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <queue>

using namespace std;
struct Node
{
    int a[5][5];
    int sta;
};
queue<Node> q;
int b[10];
int fac[10];
int vis[400000];
int pre[400000];
int ans;
int f1[10];
int f2[10];
int tran[10];
char ch[10];
bool used[10];
Node cyk;
void facfun()
{
    fac[0]=1;
    for(int i=1;i<=9;i++)
    {
        fac[i]=i*fac[i-1];
    }
}
int kt(Node q)
{
    int cnt=0;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
           b[++cnt]=q.a[i][j];
    int sum=0,num=0;
    for(int i=1;i<=9;i++)
    {
        num=0;
        for(int j=i+1;j<=9;j++)
        {
            if(b[i]>b[j])
                num++;
        }
        sum+=num*fac[9-i];
    }
    return sum;
}
void bfs(Node t)
{
    q.push(t);
    vis[t.sta]=1;
	pre[t.sta]=0;
    while(!q.empty())
    {
        Node term=q.front();
        q.pop();
        for(int i=1;i<=12;i++)
        {

            Node temp=term;
            if(i<=3)
			{
				temp.a[i][1]=term.a[i][3];
				temp.a[i][2]=term.a[i][1];
				temp.a[i][3]=term.a[i][2];
			}
            else if(i>3&&i<=6)
			{
                temp.a[i-3][1]=term.a[i-3][2];
				temp.a[i-3][2]=term.a[i-3][3];
				temp.a[i-3][3]=term.a[i-3][1];
			}
            else if(i>6&&i<=9)
			{
                temp.a[1][i-6]=term.a[3][i-6];
				temp.a[2][i-6]=term.a[1][i-6];
				temp.a[3][i-6]=term.a[2][i-6];
			}
            else if(i>9&&i<=12)
			{
                temp.a[1][i-9]=term.a[2][i-9];
				temp.a[2][i-9]=term.a[3][i-9];
				temp.a[3][i-9]=term.a[1][i-9];
			}
            int state=kt(temp);
            if(vis[state])
                continue;

            temp.sta=state;
            vis[state]=1;
            pre[state]=pre[term.sta]+1;

            q.push(temp);
        }

    }
}
void init()
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
	facfun();
    Node st;int cnt=0;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
           st.a[i][j]=++cnt;
    st.sta=0;
    bfs(st);
}
int anspos;
void dfs(int i)
{
	if(i==10)
	{
		/*for(int p=1;p<=3;p++)
		{
			for(int k=1;k<=3;k++)
			{
				cout<<cyk.a[p][k]<<" ";
			}
			cout<<endl;
		}*/
		int c=pre[kt(cyk)];
		if(c==-1) return;
		ans=min(ans,c);return;
	}
	if(f2[i]==0)
	{
		for(int j=1;j<=9;j++)
		{
			if(!used[j])
			{
				used[j]=true;
				int y=i%3,x;
				if(y==0){x=i/3;y=3;}
				else {x=i/3+1;}
				cyk.a[x][y]=j;
				dfs(i+1);
				used[j]=false;
			}
		}
	}
	else
	{
         int y=i%3,x;
		 if(y==0){x=i/3;y=3;}
		 else {x=i/3+1;}
		 cyk.a[x][y]=f2[i];
		 dfs(i+1);
	}

}

int main()
{
    int t;
    scanf("%d",&t);
    init();
    int cas=0;
    while(t--)
    {
		memset(used,0,sizeof(used));
		for(int i=1;i<=9;i++)
		{
			scanf("%d",&f1[i]);
			tran[f1[i]]=i;
		}
        for(int i=1;i<=9;i++)
		{
			scanf("%s",ch);
			f2[i]=ch[0]-'0';
			if(f2[i]>=1&&f2[i]<=9)
				f2[i]=tran[f2[i]],used[f2[i]]=true;
			else
				f2[i]=0;
		}
        ans=1000000;
        dfs(1);
		if(ans>=1000000)
			printf("Case #%d: No Solution!\n",++cas);
		else
			printf("Case #%d: %d\n",++cas,ans);
    }
    return 0;
}
时间: 2024-08-03 00:59:56

UESTC 485 Game(康托,BFS)的相关文章

CDOJ 485 UESTC 485 Game

题意:八数码,但是转移的方式是转动,一共十二种,有多组询问,初态唯一,终态不唯一. 题解:初态唯一,那么可以预处理出012345678的所有转移情况,然后将初态对012345678做一个映射,再枚举一下终态的所有情况,取最小值即可. 不得不学了逆cantor展开,cantor展开是一个变进制数,每位上是原序列对应位置上的逆序值.那么求逆时候,就先除最大的位权得到对应位置上的逆序值,根据逆序值可以知道他在原序列中第几大,然后标记它,迭代.状态转移有点烦.一开始还担心超时,就打了个表直接存到程序里,

hdu 5012 bfs 康托展开

Dice Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 491    Accepted Submission(s): 290 Problem Description There are 2 special dices on the table. On each face of the dice, a distinct number w

Aizu 0121 Seven Puzzle (康托展开+bfs)

Seven Puzzle Time Limit : 1 sec, Memory Limit : 65536 KB 7パズルは8つの正方形のカードとこれらのカードがぴたりと収まる枠を使って行います.それぞれのカードは互いに区別できるように.0,1,2....7と番号がつけられています.枠には.縦に2個.横に4個のカードを並べることができます. 7パズルを始めるときには.まず枠にすべてのカードを入れます.枠のなかで0のカードだけは.上下左右に隣接するカードと位置を交換することができます.たとえば.枠

HDU 3567 Eight II 打表,康托展开,bfs,g++提交可过c++不可过 难度:3

http://acm.hdu.edu.cn/showproblem.php?pid=3567 相比Eight,似乎只是把目标状态由确定的改成不确定的,但是康托展开+曼哈顿为h值的A*和IDA*都不过,而且也不好控制字典序 换个角度想,虽然起始状态有很多,但是到底哪一位是1,哪一位是2不是最重要的,最重要的是和目标状态对应,所以可以把起始状态重新编码为"12345678"这种形式(先不考虑X),然后目标状态也对应过去,当考虑X的时候,我们可以认为起始状态只有9种,分别是'X'在各个位置的

HDU 1043 Eight(反向BFS+打表+康托展开)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目大意:传统八数码问题 解题思路:就是从“12345678x”这个终点状态开始反向BFS,将各个状态记录下来,因为数字太大所以用康托展开将数字离散化. 代码: 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<st

hdu 1430 (BFS 康托展开 或 map )

第一眼看到这题就直接BFS爆搜,第一发爆了内存,傻逼了忘标记了,然后就改,咋标记呢. 然后想到用map函数,就8!个不同的排列,换成字符串用map标记.然后又交一发果断超时,伤心,最恨超时,还不如来个wa算了. 然后卡着了,后来上网上搜了,要用康托展开,康托展开是什么鬼?然后学习了一下,就是个映射,感觉和map差不多. http://blog.csdn.net/zhongkeli/article/details/6966805这个学习一下康托展开. 其实本题的关键不是康托展开,而是置换. 以12

HDU1430 BFS + 打表 + 康托展开

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430 , 一道比较好的题. 这道题要用到很多知识,康托展开.BFS.打表的预处理还要用到一一映射,做完受益匪浅. 其实这道题也可以用双向BFS来写,思路也已经有了,过几天再来写. 本文持续更新. 先说搜索部分: 对于魔板的每一个状态,都可以进行A.B.C三种操作,所以按照图论来讲,就是操作前的状态可以到达操作后的状态,所以就这样转换成了广搜问题. 这里要注意一点,由于题目要求字典序最小的,所以搜索的

poj 1077 八数码(BFS+康托展开)

1 /* 2 题意:八数码问题,给出3*3的矩阵含1~8以及x,给出一个符合的解使得移动后的矩阵的顺序为1~8,最后为x 3 4 题解:BFS 5 需要用到康托展开来表示状态,不然数组无法完全表示所有状态,这样BFS就无法判断找不到解的情况(status 6 的0ms,0KB究竟是怎么做到的,简直不能想象=.=) 7 */ 8 #include <cstdio> 9 #include <cstring> 10 #include <queue> 11 #include &

POJ 1077 Eight(康托展开+BFS)

Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   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