六数码 广搜例题 附带一些实用的小用法
2017-11-16 11:42
204 查看
六数码这道题本身是一道广搜的例题 主要部分是广搜模版 大多数人已重复多遍 应该已经掌握 所以我在此说一下小细节 反正模版我是会的 小细节我真的不会
看大佬的博客学会了这些细节 在这里把精华详细地说出来 b数在心 大佬勿笑 如有不对 还望指正
但是这些小细节只能一点一点积累了
1.队列的清空 操作如下
while(!q1.empty())
{
q1.pop(); // 队首元素一直出队直到队列为空达到清空队列的作用
}
2.used的清空 used数组是定义在map这个头文件上面的
used.clear
3.具体怎么输出的问题
我发现这个题目提交的时候有个bug 我用了本来写好的程序提交是对的 然后改了一点提交也是对的 这就比较纠结了 我又看了一遍题目 发现我犯了一个比较扯淡的错误
我觉得这个问题应该不只我一个人犯吧 只有我当时脑子短路我也是比较无奈的
输出方法1 : 输入一个测例 输出一个测例的结果 如此运行下去 这么提交是对的 但是不符合题意 题意应该是一口气输出多个测例的结果 这个问题应该比较常见 应避免
效果大概是这样的 (在这里我只列举两个测例):
第一步 : 输入 1 3 2 4 5 6
第二步 : 回车 这时候就输出 No 了 (明显不符合题意)
第三步 :再输入 1 3 2 4 5 6
第四步 : 回车 这时候还输出 No
第五步 : 按ctrl+z
第六步 : 回车 程序结束
输出方法2 : 在我思考人生之后觉得这么理解应该是比较正确的 用一个数组存一下每个测例得出的结果 最后再一口气输出全部测例的结果
改正后的效果
第一步 : 输入 1 3 2 4 5 6
第二步 : 回车 这时候不会输出
第三步 :再输入 1 3 2 4 5 6
第四步 : 回车 这时候还不会输出
第五步 : 按ctrl+z
第六步 : 回车 输出结果程序结束 (这时候我就觉得效果比较符合题意了 如果我的理解有问题 还望指正 共同进步)
题目和代码如下
现有一两行三列的表格如下:
A B C
D E F
把1、2、3、4、5、6六个数字分别填入A、B、C、D、E、F格子中,每个格子一个数字且各不相同。每种不同的填法称为一种布局。如下:
1 3 5
2 4 6
布局1
2 5 6
4 3 1
布局2
定义α变换如下:把A格中的数字放入B格,把B格中的数字放入E格,把E格中的数字放入D格,把D格中的数字放入A格。
定义β变换如下:把B格中的数字放入C格,把C格中的数字放入F格,把F格中的数字放入E格,把E格中的数字放入B格。
问:对于给定的布局,可否通过有限次的α变换和β变换变成下面的目标布局:
1 2 3
4 5 6
目标布局
输入:
本题有多个测例,每行一个,以EOF为输入结束标志。每个测例的输入是1到6这六个数字的一个排列,空格隔开,表示初始布局ABCDEF格中依次填入的数字。
输出:
每个输出占一行。可以转换的,打印Yes;不可以转换的,打印No。
输入样例:
1 3 5 2 4 6
2 5 6 4 3 1
输出样例:
No
Yes
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<queue>//队列解决广搜问题
#include<map>//使用map是为了方便标记
#include<stdlib.h>
using namespace std ;
queue<int>q1 ;
map<int , int> used ;//判断是否遍历过
int bfs() ; //广搜找答案
int moveto(int u , int dire) ;
void print(int n) ;
//1 3 5 2 4 6
//2 5 6 4 3 1
int main()
{
int num = 0 , i , m , n , a[100] , counter = 0 ;
while(scanf("%d",&m)!=EOF)//以EOF为结束标志
{
num = m ;
for(i = 0 ; i < 5 ; i++)
{
scanf("%d" , &m);
num = num * 10 + m ;
}//将输入的布局直接转为6位数
while(!q1.empty()) // 队首一直出队直到队列为空
{
q1.pop();
}
used.clear();//多组数据 需要清空used
q1.push(num);//将起点加入队列
used[num]=1;
a[counter] = bfs() ;//输出搜索的结果
counter ++ ;
}
for(i = 0 ; i < counter ; i++)
{
if(a[i]==0) printf("No\n");//输出结果
if(a[i]==1) printf("Yes\n");
}
return 0;
}
int bfs()//广搜找答案 这个子函数是广搜的模版 已练习多遍
{
int i , u , v ;
while(!q1.empty())
{
u = q1.front() ;
q1.pop() ;
for(i = 1 ; i <= 2 ; i++)
{
v = moveto (u , i) ;
if(v == 123456)
{
return 1 ;//找的到解 return 1
}
if(used.count(v) == 0)
{
q1.push(v) ;
used[v] = 1 ;
}
}
}
return 0 ;//找不到解 return 0
}
int moveto(int u , int dire)
{
/*定义α 把A b[0][0] B b[0][1],把B b[0][1] E b[1][1],把E b[1][1] D b[1][0],把D b[1][0] A b[0][0]。
定义β 把B b[0][1] C b[0][2],把C b[0][2] F b[1][2],把F b[1][2] E b[1][1],把E b[1][1] B b[0][1]
*/
int i , j , b[2][3] , v = 0 , temp1 , temp2 , temp3 , temp4 ;
if(dire == 1) // a转换
{
for(i = 1 ; i >= 0 ; i--)
{
for(j = 2 ; j >= 0 ; j--)
{
b[i][j] = u % 10 ;
u /= 10 ;
}
}
temp1 = b[0][0] ;//设置多个临时变量方便转换
temp2 = b[0][1] ;
temp3 = b[1][1] ;
temp4 = b[1][0] ;
b[0][1] = temp1 ;
b[1][1] = temp2 ;
b[1][0] = temp3 ;
b[0][0] = temp4 ;
for(i = 0 ; i <= 1 ; i++)
{
for(j = 0 ; j <= 2 ; j++)
{
v = v * 10 + b[i][j] ;
}
}
return v ;
}
//把B b[0][1] C b[0][2],把C b[0][2] F b[1][2],把F b
4000
[1][2] E b[1][1],把E b[1][1] B b[0][1]
else // b转换 方法和a相同
{
for(i = 1 ; i >= 0 ; i--)
{
for(j = 2 ; j >= 0 ; j--)
{
b[i][j] = u % 10 ;
u /= 10 ;
}
}
temp1 = b[0][1] ;
temp2 = b[0][2] ;
temp3 = b[1][2] ;
temp4 = b[1][1] ;
b[0][2] = temp1 ;
b[1][2] = temp2 ;
b[1][1] = temp3 ;
b[0][1] = temp4 ;
for(i = 0 ; i <= 1 ; i++)
{
for(j = 0 ; j <= 2 ; j++)
{
v = v * 10 + b[i][j] ;
}
}
return v ;
}
}
六数码这道题本身是一道广搜的例题 主要部分是广搜模版 大多数人已重复多遍 应该已经掌握 所以我在此说一下小细节 反正模版我是会的 小细节我真的不会
看大佬的博客学会了这些细节 在这里把精华详细地说出来 b数在心 大佬勿笑 如有不对 还望指正
但是这些小细节只能一点一点积累了
1.队列的清空 操作如下
while(!q1.empty())
{
q1.pop(); // 队首元素一直出队直到队列为空达到清空队列的作用
}
2.used的清空 used数组是定义在map这个头文件上面的
used.clear
3.具体怎么输出的问题
我发现这个题目提交的时候有个bug 我用了本来写好的程序提交是对的 然后改了一点提交也是对的 这就比较纠结了 我又看了一遍题目 发现我犯了一个比较扯淡的错误
我觉得这个问题应该不只我一个人犯吧 只有我当时脑子短路我也是比较无奈的
输出方法1 : 输入一个测例 输出一个测例的结果 如此运行下去 这么提交是对的 但是不符合题意 题意应该是一口气输出多个测例的结果 这个问题应该比较常见 应避免
效果大概是这样的 (在这里我只列举两个测例):
第一步 : 输入 1 3 2 4 5 6
第二步 : 回车 这时候就输出 No 了 (明显不符合题意)
第三步 :再输入 1 3 2 4 5 6
第四步 : 回车 这时候还输出 No
第五步 : 按ctrl+z
第六步 : 回车 程序结束
输出方法2 : 在我思考人生之后觉得这么理解应该是比较正确的 用一个数组存一下每个测例得出的结果 最后再一口气输出全部测例的结果
改正后的效果
第一步 : 输入 1 3 2 4 5 6
第二步 : 回车 这时候不会输出
第三步 :再输入 1 3 2 4 5 6
第四步 : 回车 这时候还不会输出
第五步 : 按ctrl+z
第六步 : 回车 输出结果程序结束 (这时候我就觉得效果比较符合题意了 如果我的理解有问题 还望指正 共同进步)
题目和代码如下
现有一两行三列的表格如下:
A B C
D E F
把1、2、3、4、5、6六个数字分别填入A、B、C、D、E、F格子中,每个格子一个数字且各不相同。每种不同的填法称为一种布局。如下:
1 3 5
2 4 6
布局1
2 5 6
4 3 1
布局2
定义α变换如下:把A格中的数字放入B格,把B格中的数字放入E格,把E格中的数字放入D格,把D格中的数字放入A格。
定义β变换如下:把B格中的数字放入C格,把C格中的数字放入F格,把F格中的数字放入E格,把E格中的数字放入B格。
问:对于给定的布局,可否通过有限次的α变换和β变换变成下面的目标布局:
1 2 3
4 5 6
目标布局
输入:
本题有多个测例,每行一个,以EOF为输入结束标志。每个测例的输入是1到6这六个数字的一个排列,空格隔开,表示初始布局ABCDEF格中依次填入的数字。
输出:
每个输出占一行。可以转换的,打印Yes;不可以转换的,打印No。
输入样例:
1 3 5 2 4 6
2 5 6 4 3 1
输出样例:
No
Yes
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<queue>//队列解决广搜问题
#include<map>//使用map是为了方便标记
#include<stdlib.h>
using namespace std ;
queue<int>q1 ;
map<int , int> used ;//判断是否遍历过
int bfs() ; //广搜找答案
int moveto(int u , int dire) ;
void print(int n) ;
//1 3 5 2 4 6
//2 5 6 4 3 1
int main()
{
int num = 0 , i , m , n , a[100] , counter = 0 ;
while(scanf("%d",&m)!=EOF)//以EOF为结束标志
{
num = m ;
for(i = 0 ; i < 5 ; i++)
{
scanf("%d" , &m);
num = num * 10 + m ;
}//将输入的布局直接转为6位数
while(!q1.empty()) // 队首一直出队直到队列为空
{
q1.pop();
}
used.clear();//多组数据 需要清空used
q1.push(num);//将起点加入队列
used[num]=1;
a[counter] = bfs() ;//输出搜索的结果
counter ++ ;
}
for(i = 0 ; i < counter ; i++)
{
if(a[i]==0) printf("No\n");//输出结果
if(a[i]==1) printf("Yes\n");
}
return 0;
}
int bfs()//广搜找答案 这个子函数是广搜的模版 已练习多遍
{
int i , u , v ;
while(!q1.empty())
{
u = q1.front() ;
q1.pop() ;
for(i = 1 ; i <= 2 ; i++)
{
v = moveto (u , i) ;
if(v == 123456)
{
return 1 ;//找的到解 return 1
}
if(used.count(v) == 0)
{
q1.push(v) ;
used[v] = 1 ;
}
}
}
return 0 ;//找不到解 return 0
}
int moveto(int u , int dire)
{
/*定义α 把A b[0][0] B b[0][1],把B b[0][1] E b[1][1],把E b[1][1] D b[1][0],把D b[1][0] A b[0][0]。
定义β 把B b[0][1] C b[0][2],把C b[0][2] F b[1][2],把F b[1][2] E b[1][1],把E b[1][1] B b[0][1]
*/
int i , j , b[2][3] , v = 0 , temp1 , temp2 , temp3 , temp4 ;
if(dire == 1) // a转换
{
for(i = 1 ; i >= 0 ; i--)
{
for(j = 2 ; j >= 0 ; j--)
{
b[i][j] = u % 10 ;
u /= 10 ;
}
}
temp1 = b[0][0] ;//设置多个临时变量方便转换
temp2 = b[0][1] ;
temp3 = b[1][1] ;
temp4 = b[1][0] ;
b[0][1] = temp1 ;
b[1][1] = temp2 ;
b[1][0] = temp3 ;
b[0][0] = temp4 ;
for(i = 0 ; i <= 1 ; i++)
{
for(j = 0 ; j <= 2 ; j++)
{
v = v * 10 + b[i][j] ;
}
}
return v ;
}
//把B b[0][1] C b[0][2],把C b[0][2] F b[1][2],把F b
4000
[1][2] E b[1][1],把E b[1][1] B b[0][1]
else // b转换 方法和a相同
{
for(i = 1 ; i >= 0 ; i--)
{
for(j = 2 ; j >= 0 ; j--)
{
b[i][j] = u % 10 ;
u /= 10 ;
}
}
temp1 = b[0][1] ;
temp2 = b[0][2] ;
temp3 = b[1][2] ;
temp4 = b[1][1] ;
b[0][2] = temp1 ;
b[1][2] = temp2 ;
b[1][1] = temp3 ;
b[0][1] = temp4 ;
for(i = 0 ; i <= 1 ; i++)
{
for(j = 0 ; j <= 2 ; j++)
{
v = v * 10 + b[i][j] ;
}
}
return v ;
}
}
相关文章推荐
- PullToRefresh一些实用的用法
- iBatis一些非见用法(相当实用)
- Vim一些实用的用法
- 记录一些简单实用的vim用法
- (java)StringUtil类的一些用法,特别实用
- SecureCRT(Linux平台)中的一些实用/有趣用法
- oracle 一些比较实用的用法
- Category一些(实用)用法
- oracle 一些比较实用的用法
- list的一些常见用法总结(实用干货收藏)
- iBatis一些非见用法(相当实用)
- 老码农教你学英语(附带:补充一些英语学习素材)
- JavaScript实用的一些技巧
- JavaScript实用的一些技巧
- linux date -d 的一些用法
- Apache Pig的一些基础概念及用法总结(转)
- 关于Node.js中Buffer的一些你可能不知道的用法
- PHP/TP一些避免使用的用法
- Android Studio 中的一些实用插件
- PostgreSQL和Oracle用法上的一些区别