一个类似于八数码的算法题

挨踢民工的乐章 2012-09-18 08:53:59
一个N*N的矩阵,里面的数字不一定连续(可以重复),但一定能排列成每行、每列之和都相等
在N*N的矩阵下面有两个0,代表两个空格,要求要像拼图游戏一样移动数字,

比如给定3 * 3矩阵


3,1,3
1,2,2
2,4,3
0,0


要求得出目的矩阵(列之和,行之和都为7)



1,3,3
4,1,2
2,3,2
Step:10
7D8L9L6D5R2D1R4U7U10U



后面两行分别是移动的步数和移动的过程,7D表示编号第七的数字(从1开始编号,先行后列)向下移动一次,L是左,R是右,U是向上。
...全文
255 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
gqjjqg 2012-09-29
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

引用 10 楼 的回复:

例如:
3,1,3
1,2,2
2,4,3

求和除以3 = 7
按顺序分成三行:
3 1 3

1 2 4

2 2 3


搜索第一列
3 2 2
或者
3 1 3
分别尝试其可行性。
可以得到目标矩阵。


怎么按顺序分成三行?
[/Quote]

3,1,3
1,2,2
2,4,3


按顺序 贪心一下就行了,这个随便,怎么快怎么来都行。
3,1,3 = 7
1,2,2 = 6 不符合
1,2,2 = 6 不符合
1,2,4 = 7
2,2,3 = 7



q598162221 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]

引用 13 楼 的回复:

#include<stdio.h>
int a[3][3]={3,1,3,1,2,2,2,4,3};
int m[2][4]={0,1,0,-1,
-1,0,1,0};
char b[100];
void print()
{ int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf……

有三……
[/Quote]
100的矩阵 得跑一亿次.......
q598162221 2012-09-28
  • 打赏
  • 举报
回复

//开始选择...
//此处最少得是O(n^2) 如果一百大小的矩阵(既1W个数找出任意三数想加为一固定值) 则需要运算10000*10000=!!!! 这个是动态规划得出的解
//此方法不成立....
//既然这样 只有先排序....对于32位数值用桶排序加上一个技巧 大概速度能达到O(4n) 空间需要大概是n+char[256];
//然后任意三数中找出组合为一固定值的数...
//理论......................................
//.......................如果对数组一中第一个数为参数 如果第二个数是数组中最后一个数的时候已经大于了value 马上使数组二向前移动一位 若不然 和第三个数的最后一个数相加 若大于则向前移动一位
//...................... 若小于则让数组二向前移动一位 .....解释的不是很清晰 流程如下
//.................... 第一个数 第二个数 第三个数
//....................位置 0 n n
//....................值 store[0] store[n-1] store[n-1]
//....................说明 由于 store是排序之后的数组 所以 store[n-1]为最大值 store[0]为最小值
//....................结果1 情况1:如果store[0]+store[n-1]>sum 由于只用了2个数就大于sum了.....所以第三个数不需要试了 这时候只需把store[n-1]这个向前移动一位变成 store[n-2] 继续这个步奏 如果store已经是第一个元素...则store[0]变成store[1] 继续这个步奏
//.......................... 情况2:如果store[0]+store[n-1]<=sum 现在开始看第三个值 设结果 result=store[0]+store[n-1] 既前2个的值
//....................结果2 情况1:result+store[n-1]>sum 第三个数向前移动一位 既变小 如果现在已经是最小 第二个数向前移动一位继续遍历
//............................. 情况2:如果result+store[n-1]<sum 第二个数已经最大 第三个也最大 依然小于sum....只用变第一个数 向前移动一位
//....................结果3 情况:如果第一个数到最大+1 结束循环....

//时间复杂度..............
//第一个数和第二个数的总时间复杂度为0(2n)*O(很小的值) 必须满足前两个数才会执行第三个数.... 具体不计算了
//根据每一个位置可以用2次这个性质 如果任意一个位置 已经使用了2此 则不再遍历此位置...!!!!
左眼看到鬼 2012-09-28
  • 打赏
  • 举报
回复
看着没有思路,等答案
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]

#include<stdio.h>
int a[3][3]={3,1,3,1,2,2,2,4,3};
int m[2][4]={0,1,0,-1,
-1,0,1,0};
char b[100];
void print()
{ int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf……
[/Quote]
有三个问题:
1.贴代码最后套用下代码格式。
2.贴代码最好有些注释或者思路介绍。
3.你的代码应该是没经过剪枝的深度优先遍历,而且没有记录已访问过的路径。理论上很难跑出结果
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 的回复:]

引用 13 楼 的回复:

#include<stdio.h>
int a[3][3]={3,1,3,1,2,2,2,4,3};
int m[2][4]={0,1,0,-1,
-1,0,1,0};
char b[100];
void print()
{ int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf……

没办……
[/Quote]
两个格其实是最多8种移动可能的
c090869 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]

#include<stdio.h>
int a[3][3]={3,1,3,1,2,2,2,4,3};
int m[2][4]={0,1,0,-1,
-1,0,1,0};
char b[100];
void print()
{ int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf……
[/Quote]
没办法,连业余水平都不够,呵 别见笑。
连贴代码都不会,还不知道抄上来有没有抄错,
m[2][4]是移动四个方向;b[100]记录轨迹;
从第七格开始不同方向移动,移到第8格止检查结果。
c090869 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]

引用 14 楼 的回复:

引用 13 楼 的回复:

#include<stdio.h>
int a[3][3]={3,1,3,1,2,2,2,4,3};
int m[2][4]={0,1,0,-1,
-1,0,1,0};
char b[100];
void print()
{ int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++……
[/Quote]100的距阵,此代码得跑3^10000次,此代码只适合3*3距阵。
c090869 2012-09-28
  • 打赏
  • 举报
回复
#include<stdio.h>
int a[3][3]={3,1,3,1,2,2,2,4,3};
int m[2][4]={0,1,0,-1,
-1,0,1,0};
char b[100];
void print()
{ int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf("%d ",a[i][j]);
printf("\n");
}
printf("\n");
return;
}

int test()
{ int i,j,s,r;
for(i=0;i<3;i++)
{
s=0;r=0;
for(j=0;j<3;j++)
{ s+=a[i][j]; r+=a[j][i];}
if(s!=7||r!=7)
return 0;
}
return 1;
}

void move(int x,int y,int d,int n)
{ int x1,y1,i,t,d1;
if(n>13)return;
if(x==1&&y==2)
{ if(test())
{ print(); *(b+2*n)=0; printf("7D%s7R7U\n",b);
return;

}
}
for(i=0;i<4;i++)
{
if(i==d)continue;
x1=x+m[0][i]; y1=y+m[1][i];
if(x1>=0&&x1<3&&y1>=0&&y1<3)
{
*(b+2*n)=1+3*y1+x1+48;
if(i==0) *(b+2*n+1)='D';
if(i==1) *(b+2*n+1)='L';
if(i==2) *(b+2*n+1)='U';
if(i==3) *(b+2*n+1)='R';
t=a[y][x]; a[y][x]=a[y1][x1]; a[y1][x1]=t;
d1=(i+2)%4;
move(x1,y1,d1,n+1);
t=a[y][x]; a[y][x]=a[y1][x1]; a[y1][x1]=t;
}
}
return 0;
}

void main()
{
move(0,2,2,0);
}
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

例如:
3,1,3
1,2,2
2,4,3

求和除以3 = 7
按顺序分成三行:
3 1 3

1 2 4

2 2 3


搜索第一列
3 2 2
或者
3 1 3
分别尝试其可行性。
可以得到目标矩阵。
[/Quote]

怎么按顺序分成三行?
lastseason 2012-09-26
  • 打赏
  • 举报
回复
没有思路,求高手~
gqjjqg 2012-09-25
  • 打赏
  • 举报
回复
例如:
3,1,3
1,2,2
2,4,3

求和除以3 = 7
按顺序分成三行:
3 1 3

1 2 4

2 2 3


搜索第一列
3 2 2
或者
3 1 3
分别尝试其可行性。
可以得到目标矩阵。
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

引用 7 楼 的回复:

引用 5 楼 的回复:

确定任意个N*N矩阵都能排成每行每列之和都相等?
{{99,99,99},{99,1,99},{99,99,99}}
这个能吗?

就像楼上说的,给定的矩阵一定保证可以每行每列都相等。。


找一下华容道的算法,追求追少移动次数。况且,你这里还有两个空格比一个空格更方便。


-----
没研究过这个,不过个人……
[/Quote]

这样应该可以,不过求目标矩阵有啥具体思路吗?
gqjjqg 2012-09-25
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

引用 5 楼 的回复:

确定任意个N*N矩阵都能排成每行每列之和都相等?
{{99,99,99},{99,1,99},{99,99,99}}
这个能吗?

就像楼上说的,给定的矩阵一定保证可以每行每列都相等。。
[/Quote]

找一下华容道的算法,追求追少移动次数。况且,你这里还有两个空格比一个空格更方便。


-----
没研究过这个,不过个人感觉,可以先对所有数字进行一次计算获取最终的目标矩阵状态。
然后计算由原始矩阵到目标矩阵的最少移动次数会比较方便。
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

确定任意个N*N矩阵都能排成每行每列之和都相等?
{{99,99,99},{99,1,99},{99,99,99}}
这个能吗?
[/Quote]
就像楼上说的,给定的矩阵一定保证可以每行每列都相等。。
ggshelley 2012-09-20
  • 打赏
  • 举报
回复
确定任意个N*N矩阵都能排成每行每列之和都相等?
{{99,99,99},{99,1,99},{99,99,99}}
这个能吗?
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

题意不明
[/Quote]

有啥不明白的地方,具体点?

挨着0的数字可以移动的0的位置,0就相当于拼图游戏中的空,最后移动的结果是所有每行之和和每列之和相等。
rocktyt 2012-09-20
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

确定任意个N*N矩阵都能排成每行每列之和都相等?
{{99,99,99},{99,1,99},{99,99,99}}
这个能吗?
[/Quote]
lz说的是已经知道输入的数据满足一定能排成那样的条件,不是随便输入的
  • 打赏
  • 举报
回复
求来人。。
smsgreenlife 2012-09-19
  • 打赏
  • 举报
回复
题意不明
加载更多回复(1)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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