九宫格问题,求思路!

ckcz123 2012-03-31 09:53:21
题目说明:
给定一个九宫格,里面填有1-9这9个数。
每次可以将相邻的两个数交换。
问最少几次,可以得到一个三阶幻方(每行,每列,和两条对角线上的和都是15)

输入说明:
三行,每行3个数

输出说明:
一行,为最少的步数(如果输入的就是三阶幻方,则输出0;如果不能在有限步后得到三阶幻方,输出-1)

输入样例:
1 2 8
3 5 4
6 7 8

输出样例:
5
...全文
535 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
muyi66 2012-04-01
  • 打赏
  • 举报
回复
Grid9类的代码:

grid9.h
class Grid9
{
private:
int grid[9]; // 存储着九宫状态
public:
int readGrid(int x, int y); // 读出九宫中数值
int feature(); // 返回当前九宫状态的特征值
void setGrid(int feature); // 按特征值设置九宫
void setGrid(int index, int v); // 按索引设置九宫
int difference(); // 返回当前九宫状态距离完美九宫的差距,差距为0则意味着已经是完美九宫。
void swap(int position); // 交换指定位置上的数。
};


grid9.cpp
#include <math.h>
#include "grid9.h"

int Grid9::readGrid(int x, int y)
{
if (x<0||x>2||y<0||y>2)
return 0;
else
return grid[x*3+y];
}

int Grid9::feature()
{
int sum;
sum=grid[0];
for (int i=1;i<9;i++)
sum=sum*10+grid[i];
return sum;
}

void Grid9::setGrid(int feature)
{
for (int i=8;i>=0;i++)
{
grid[i]=feature%10;
feature/=10;
}
}

void Grid9::setGrid(int index, int v)
{
if (index<0||index>8||v<1||v>9)
return;
else
grid[index]=v;
}

int Grid9::difference()
{
int sum=0;
sum+=abs(grid[0]+grid[1]+grid[2]-15);
sum+=abs(grid[3]+grid[4]+grid[5]-15);
sum+=abs(grid[6]+grid[7]+grid[8]-15);
sum+=abs(grid[0]+grid[3]+grid[6]-15);
sum+=abs(grid[1]+grid[4]+grid[7]-15);
sum+=abs(grid[2]+grid[5]+grid[8]-15);
sum+=abs(grid[0]+grid[4]+grid[8]-15);
sum+=abs(grid[2]+grid[4]+grid[6]-15);
return sum;
}

void Grid9::swap(int position)
{
static int swapGroup[12][2]={{0,1},{1,2},{3,4},{4,5},{6,7},{7,8},{0,3},{3,6},{1,4},{4,7},{2,5},{5,8}};
if (position<0||position>=12)
return;
int temp,front,later;
front=swapGroup[position][0];
later=swapGroup[position][1];
temp=grid[front];
grid[front]=grid[later];
grid[later]=temp;
return;
}
muyi66 2012-04-01
  • 打赏
  • 举报
回复
试验了一种方式,得到解答大约需要几秒钟:

用递归做深度搜索,限制最大深度为40级。因为只要30多级就能保证把每一个数字送到指定地方了,不必搜太多。

每当搜索到一个解答,则更新最大深度限制,保证后面的搜索不会有更多浪费。

若当前还需要继续深入搜索,则循环列出所有12种改变并进行测试。当改变发生后没有出现曾有过的重复状态,则递归搜索。

代码如下:
#include <iostream>
#include "grid9.h"

using namespace std;

struct notes
{
int n[40];
int top;
}route; // 用于记录路径
Grid9 grid; // 九宫格
int minDepth=40; // 记录最少步骤的步数

void inputG9();
void findG9(int depth);
int existing(int feature);

void main()
{
route.top=0; // 清空记录
inputG9(); // 输入原始数据
cout<<endl<<"开始计算步骤:"<<endl;
findG9(0); // 调用搜索程序
cout<<"最少需要"<<minDepth<<"步"<<endl; // 输出最小步骤数
system("pause");
}

void inputG9()
{
int in[9];

cout<<"请输入原始九宫数据:"<<endl;
cout<<"第一行:";
cin>>in[0]>>in[1]>>in[2];
cout<<"第二行:";
cin>>in[3]>>in[4]>>in[5];
cout<<"第三行:";
cin>>in[6]>>in[7]>>in[8];

for (int i=0;i<9;i++)
grid.setGrid(i,in[i]);
}

void findG9(int depth)
{
int gd=grid.difference();
route.n[route.top++]=gd;

if (gd==0) // 得到一个解
{
minDepth=depth;
route.top--;
return;
}
if (depth==minDepth) // 已经到了最大深度,回溯
{
route.top--;
return;
}
for (int i=0;i<12;i++)
{
grid.swap(i); // 交换i位置数据
gd=grid.difference();
if (!existing(gd))
findG9(depth+1); // 递归查找
grid.swap(i); // 恢复i位置数据
}
route.top--;
}

int existing(int feature)
{
for (int i=route.top-1;i>=0;i--)
if (feature==route.n[i])
return 1;
return 0;
}
ckcz123 2012-04-01
  • 打赏
  • 举报
回复
我已经晕了。。。
一道noi的题目被你们折腾成什么样子。。。
muyi66 2012-04-01
  • 打赏
  • 举报
回复
可以输出最短步骤的daima:
#include <iostream>
#include "grid9.h"

using namespace std;

struct notes
{
int n[40];
int top;
}route,minRoute; // 用于记录路径
Grid9 grid; // 九宫格
int minDepth; // 记录最少步骤的步数

void inputG9();
void findG9(int depth);
int existing(int feature);
void showRoute();

void main()
{
char ch;
while (1)
{
route.top=0; // 清空记录
minRoute.top=0;
minDepth=10; // 测试中没有发现超过8步的组合,如果能证明这一点,把这个数字改成10就能加速很多了
inputG9(); // 输入原始数据
cout<<endl<<"开始计算步骤:"<<endl;
findG9(0); // 调用搜索程序
cout<<"最少需要"<<minDepth<<"步"<<endl;
showRoute(); // 输出最小步骤
cout<<"------end------"<<endl<<"还要继续吗?(Y/N)";
cin>>ch;
if (ch=='N'||ch=='n')
break;
}
}

void inputG9()
{
int in[9];

cout<<"请输入原始九宫数据:"<<endl;
cout<<"第一行:";
cin>>in[0]>>in[1]>>in[2];
cout<<"第二行:";
cin>>in[3]>>in[4]>>in[5];
cout<<"第三行:";
cin>>in[6]>>in[7]>>in[8];

for (int i=0;i<9;i++)
grid.setGrid(i,in[i]);
}

void findG9(int depth)
{
route.n[route.top++]=grid.feature();

if (grid.difference()==0) // 得到一个解
{
if (depth<minDepth)
{
cout<<"最短步骤已经下降到"<<depth<<endl;
minDepth=depth;
minRoute=route;
}
route.top--;
return;
}
if (depth==minDepth) // 已经到了最大深度,回溯
{
route.top--;
return;
}
for (int i=0;i<12;i++)
{
grid.swap(i); // 交换i位置数据
if (!existing(grid.feature()))
findG9(depth+1); // 递归查找
grid.swap(i); // 恢复i位置数据
}
route.top--;
}

int existing(int feature)
{
for (int i=route.top-1;i>=0;i--)
if (feature==route.n[i])
return 1;
return 0;
}

void showRoute()
{
cout<<endl<<"具体路径如下"<<endl;
for (int i=0;i<minRoute.top;i++)
{
cout<<"步骤"<<i<<endl;
cout<<' '<<minRoute.n[i]/1000000<<endl;
cout<<' '<<minRoute.n[i]/1000%1000<<endl;
cout<<' '<<minRoute.n[i]%1000<<endl;
cout<<endl;
if ((i+1)%3==0&&i<minRoute.top-1)
system("pause");
}
}
muyi66 2012-04-01
  • 打赏
  • 举报
回复
为了避免用户误以为死机,加一个进程显示在里面......有点破坏完美的感觉
void findG9(int depth)
{
route.n[route.top++]=grid.feature();

if (grid.difference()==0) // 得到一个解
{
if (depth<minDepth)
cout<<"最短步骤已经下降到"<<depth<<endl;
minDepth=depth;
route.top--;
return;
}
if (depth==minDepth) // 已经到了最大深度,回溯
{
route.top--;
return;
}
for (int i=0;i<12;i++)
{
grid.swap(i); // 交换i位置数据
if (!existing(grid.feature()))
findG9(depth+1); // 递归查找
grid.swap(i); // 恢复i位置数据
}
route.top--;
}
muyi66debug 2012-04-01
  • 打赏
  • 举报
回复
10楼代码有严重错误,现予更正。

不过正确的代码却没那么好运气,速度减慢了不是一点半点啊。
#include <iostream>
#include "grid9.h"

using namespace std;

struct notes
{
int n[40];
int top;
}route; // 用于记录路径
Grid9 grid; // 九宫格
int minDepth=36; // 记录最少步骤的步数

void inputG9();
void findG9(int depth);
int existing(int feature);

void main()
{
route.top=0; // 清空记录
inputG9(); // 输入原始数据
cout<<endl<<"开始计算步骤:"<<endl;
findG9(0); // 调用搜索程序
cout<<"最少需要"<<minDepth<<"步"<<endl; // 输出最小步骤数
system("pause");
}

void inputG9()
{
int in[9];

cout<<"请输入原始九宫数据:"<<endl;
cout<<"第一行:";
cin>>in[0]>>in[1]>>in[2];
cout<<"第二行:";
cin>>in[3]>>in[4]>>in[5];
cout<<"第三行:";
cin>>in[6]>>in[7]>>in[8];

for (int i=0;i<9;i++)
grid.setGrid(i,in[i]);
}

void findG9(int depth)
{
route.n[route.top++]=grid.feature();

if (grid.difference()==0) // 得到一个解
{
minDepth=depth;
route.top--;
return;
}
if (depth==minDepth) // 已经到了最大深度,回溯
{
route.top--;
return;
}
for (int i=0;i<12;i++)
{
grid.swap(i); // 交换i位置数据
if (!existing(grid.feature()))
findG9(depth+1); // 递归查找
grid.swap(i); // 恢复i位置数据
}
route.top--;
}

int existing(int feature)
{
for (int i=route.top-1;i>=0;i--)
if (feature==route.n[i])
return 1;
return 0;
}
ckcz123 2012-03-31
  • 打赏
  • 举报
回复
错了,输入是
1 2 8
3 5 4
6 7 9

抱歉,打错了。。
muyi66 2012-03-31
  • 打赏
  • 举报
回复
不止四种
疼你 2012-03-31
  • 打赏
  • 举报
回复
感觉不是很好做这题,毕竟有四种
438 816 672 294
951 357 159 753
276 492 834 618
要比较这四种结果需要多少步,输出最少的。。感觉有点麻烦。

wenke311 2012-03-31
  • 打赏
  • 举报
回复

步数最少就不好办啊
多少步之内能完成,还可能不太难
ckcz123 2012-03-31
  • 打赏
  • 举报
回复
只能横竖,不能斜。。。。

原题:http://sznoi.cn/oj/ShowProblem?problemid=v021

muyi66 2012-03-31
  • 打赏
  • 举报
回复
构造一个幻方不难,但楼主这个题要求只能用邻近交换的方法来做,这个就有点难度了。

在问下楼主:“每次可以将相邻的两个数交换”,这个“相邻”怎么定义的?水平和垂直方向肯定算,斜向的呢?
pathuang68 2012-03-31
  • 打赏
  • 举报
回复
看看这个吧:
http://baike.baidu.com/view/1905316.htm

里面有各种魔方矩阵的构造方法。
面包大师 2012-03-31
  • 打赏
  • 举报
回复
这个算法个人感觉真的很难实现。。。
ckcz123 2012-03-31
  • 打赏
  • 举报
回复
没人有木有啊!!!

64,688

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧