15年(上)周赛2(2015-03-15) Problem A Aizu 0121
来源:互联网 发布:移动售楼软件 编辑:程序博客网 时间:2024/06/06 00:29
To 学弟学妹们,经过仔细阅读,首先理解了题目是要我们求给定一个2*4的带号码的方格,每次可以交换 0和相邻的数,问给定起始状态,最少需要多少步交换可以达到目标状态 (不要问我为什么日语这么屌)
0 1 2 3
4 5 6 7
典型的八数码问题,这里用到bfs求出所有解,说一下通常解法。
从起点状态开始,上下左右扩展所有可能情况,若遇到最终状态,则输出。
怎样判断一个状态之前已经扩展过,避免死循环?这里我给出一些特殊的技巧。(更深的知识还有很多探讨的地方,大家可以关注我5月份的讲座)
由于是判断一个全排列是否出现过
1、这里可以利用康拓展开,将全排列一一映射到一个数字,比如
0 1 2 3 4 5 6 7 --> 1
0 1 2 3 4 5 7 6 --> 2
具体的如何映射,包括原理可以自行百度 康托展开,或者看代码。【这里的映射是一一映射,所以不需要用到Hash表,我下面的代码这里多写了,大家无视就好】
2、也可以利用Hash,设置一个Hash函数,将序列Hash成一个整数,经过模运算存在数组里,例如∑a[i]*2^i。
【Hash表的相关操作大家可以看我刚刚叫大家无视的部分】
3、或者利用C++自带的STL中的map,将序列定义为String字符串,然后直接利用map判重。
但是这题由于终点状态是固定的,并且输入很多(1000组),那么一组一组计算的话,同样会很慢,所以我们还需要另一个技巧,那就是反向搜索,一次性保存所有状态的答案。也就是做一次预处理,那么对于后面的输入就可以直接输出了。
代码写的太挫,实在不想粘贴上来,姑妄写之,姑妄看之
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream>#include<cmath>#include<map>#include<queue>using namespace std; struct node{int mp[2][4];int dis;int x,y;}f,t;int FLAG;int dx[]={-1,1,0,0};int dy[]={0,0,-1,1};bool isok(int x,int y){return x>=0&&x<2&&y>=0&&y<4;}int ca[]={1,1,2,6,24,120,720,5040,40320,362880}; int ANS[1000007];int cantor(node &t) { int sum=0,cnt=0; int s[9]; for(int i=0;i<2;i++) { for(int j=0;j<4;j++) { s[cnt++]=t.mp[i][j]; } } for(int i=0;i<8;i++) { int num=0; for(int j=i+1;j<8;j++) if(s[j]<s[i]) num++; sum+=(num*ca[8-i-1]); } return sum+1; } const int MAXN=1000007;int Hash[MAXN];const int END=1;bool HashInsert(int value,int dis) //就是这里 ,无视它{ int v=value%MAXN; while(Hash[v]!=-1&&Hash[v]!=value){ v+=10; v%=MAXN; } if(Hash[v]==-1){ ANS[v]=dis; Hash[v]=value; return true; } return false; }bool isvis(node &t,int dis){int val=cantor(t);if(val==END) FLAG=1;return HashInsert(val,dis);}bool over(node &t){int cro=0;for(int i=0;i<2;i++){for(int j=0;j<4;j++){if(t.mp[i][j]!=cro) return false;cro++;}}return true;}void bfs(){FLAG=0;queue<node> q;q.push(f);while(!q.empty()){f=q.front();q.pop();for(int d=0;d<4;d++){t=f;t.x=f.x+dx[d];t.y=f.y+dy[d];if(isok(t.x,t.y)){t.dis++;swap(t.mp[f.x][f.y],t.mp[t.x][t.y]);if(isvis(t,t.dis))//标记 {q.push(t);}}}}}int main(){memset(Hash,-1,sizeof(Hash));f.dis=0;int cnt=0;for(int i=0;i<2;i++){for(int j=0;j<4;j++){f.mp[i][j]=cnt++;}}f.x=0;f.y=0;Hash[1]=1;ANS[1]=0;bfs();while(~scanf("%d",&f.mp[0][0])){f.dis=0;for(int i=1;i<=3;i++) scanf("%d",&f.mp[0][i]);for(int i=0;i<=3;i++) scanf("%d",&f.mp[1][i]);printf("%d\n",ANS[cantor(f)]);}return 0;}
0 0
- 15年(上)周赛2(2015-03-15) Problem A Aizu 0121
- nyoj.216 A problem is easy【水题】 2015/03/15
- Aizu 0121 Seven Puzzle
- Aizu
- Aizu
- Aizu
- Aizu
- Aizu
- Aizu
- Aizu
- Aizu
- Aizu
- Aizu
- aizu-ALDS1——A stack
- 2:A-B Problem
- a+b problem 2
- ACM上的第一道题目!A + B Problem
- UVA - 10181 15-Puzzle Problem(15数码 A*)
- 静态和非静态成员,函数之间到底区别在哪里
- Apple Watch人机交互指南:UI设计基础--App 剖析
- 2、Add Two Numbers
- CopyOnWriteArrayList 解读
- Android的各种onTouch
- 15年(上)周赛2(2015-03-15) Problem A Aizu 0121
- Apple Watch人机交互指南:UI设计基础--Glances
- CopyOnWriteArrayList详解
- qt下控制台输出中文
- java 中 使用Calendar类来获取当前时间
- Keil C 编译器常见警告与错误信息的解决方法
- leetcode_111_Minimum Depth of Binary Tree
- 很有用的cv牛人的网址和主要贡献
- hdu 3361 ASCII(模拟)