数码问题,就不介绍了,百度百度,嘿嘿。
做了一天的数码,郁闷,- -
1、判断数码问题是否有解
原文地址:http://blog.csdn.net/hnust_xiehonghao/article/details/7951173
个人总结:
数码问题判断有解总结:把0看做可移动空格,这里所说的逆序数都是除开0的
一维N:
状态s和状态e的逆序数奇偶性相同,则可相互到达;反之不行
二维N*N:
空格距离:空格位置所在的行到目标空格所在的行步数(不计左右距离)
当N为奇数:状态s和状态e的逆序数奇偶性相同,则可相互到达;反之不行
当N为偶数:状态s和状态e的逆序数奇偶性相同 && 空格距离为偶数 或者 逆序数奇偶性不同 && 空格距离为奇数,则可相互到达;反之不行
三维N*N*N:
空格距离:空格位置到目标状态空格位置的yz方向的距离之和
判断同二维
SWUST OJ 306
15数码问题(0306)
问题描述
将1,2、、14,15这15个数字填入一个4*4的方格中,当然你会发现有个空格方格,我们用数字0来代替那个空格,如下就是一个合理的填入法: 1 2 3 4 5 6 7 8 9 10 0 12 13 14 11 15 现在的问题是:你是否能通过交换相邻的两个数字(相邻指的是上、下、左、右四个方向,而且待交换的两个数字中有一个为数字0),最后变成如下这种排列格式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
输入
输入包括两部分: 第一部分:输入一个数C,代表下面共有C组输入 第二部分:输入包括一个4*4的矩阵,矩阵中的数由0,1,2、、15组成。
输出
如果能通过如题方式达到目标排列,输出“YES”,否则输出“NO”。
样例
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int main() { int a[20],T,i,j; int tot,pos,dis; scanf("%d",&T); while(T--) { tot=0; for(i=0;i<16;i++) { scanf("%d",&a[i]); if(a[i]) { for(j=0;j<i;j++) { if(a[j]>a[i]) tot++; } } else pos=i; } dis=4-(pos/4+1); if(tot%2==dis%2) cout<<"YES "; else cout<<"NO "; } return 0; }
2、POJ 1077
Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 25376 | Accepted: 11106 | Special Judge |
Description
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
由于这道题是一组数据,所以需要快速解决问题,使用A*算法
好像暴力也可过,不过耗时久,我交了一个,刚好1000MS,好神奇
16MS
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <cmath> using namespace std; #define N 400000 int get_h(const char s[]) //估价函数,返回当前状态所有数字与其位置之差的绝对值之和 { int sum=0; for(int i=0;i<9;i++) { sum+=abs(s[i]-'0'-i-1); } return sum; } struct Eight { int x; int g; char s[9]; bool operator < (const Eight &t)const { return g+get_h(s)>t.g+get_h(t.s); } }; int xpos; char s[10]; int way[N]; int pre[N]; bool vis[N]; char Dir[5]="udlr"; int dir[4][2]={-1,0,1,0,0,-1,0,1}; int fac[]={1,1,2,6,24,120,720,5040,40320,326880}; int Find(char s[]) { int i,j,k,res=0; bool has[10]={0}; for(i=0;i<9;i++) { for(k=0,j=1;j<s[i]-'0';j++) if(!has[j]) k++; res+=k*fac[8-i]; has[s[i]-'0']=1; } return res+1; } void show() { char ans[N]; int len=0,pos=1; while(pre[pos]) { ans[len++]=way[pos]; pos=pre[pos]; } for(int i=len-1;i>=0;i--) { printf("%c",ans[i]); } printf(" "); } void bfs() { Eight now,next; priority_queue<Eight> q; memset(vis,0,sizeof(vis)); memset(pre,0,sizeof(pre)); memset(way,0,sizeof(way)); now.g=0; now.x=xpos; strcpy(now.s,s); q.push(now); vis[Find(now.s)]=1; while(!q.empty()) { now=q.top(); q.pop(); if(vis[1]) { show(); return; } int pos1=Find(now.s); int x=now.x/3; int y=now.x%3; for(int i=0;i<4;i++) { next=now; int tx=x+dir[i][0]; int ty=y+dir[i][1]; if(tx>=0 && tx<=2 && ty>=0 && ty<=2) { next.g+=1; next.x=tx*3+ty; swap(next.s[now.x],next.s[next.x]); int pos2=Find(next.s); if(!vis[pos2]) { vis[pos2]=1; way[pos2]=Dir[i]; pre[pos2]=pos1; q.push(next); } } } } cout<<"unsolvable "; } int main() { while(scanf(" %c",&s[0])!=EOF) { for(int i=0;i<9;i++) { if(i) scanf(" %c",&s[i]); if(s[i]=='x') { s[i]='9'; xpos=i; } } bfs(); } return 0; }
3、HDU 1043
Eight
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12761 Accepted Submission(s): 3475
Special Judge
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
题目描述都是一样的,不过这个是多组数据,所以需要预处理
思路同"魔板":http://www.cnblogs.com/hate13/p/4198053.html
109MS
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <queue> using namespace std; #define N 400000 struct Eight { int x; //x记录X的位置 char s[9]; }; int pre[N]; bool vis[N]; char way[N]; char Dir[5]="durl"; int dir[4][2]={-1,0,1,0,0,-1,0,1}; int fac[]={1,1,2,6,24,120,720,5040,40320,326880}; int Find(char s[]) { int i,j,k,res=0; bool has[10]={0}; for(i=0;i<9;i++) { for(k=0,j=1;j<s[i]-'0';j++) if(!has[j]) k++; res+=k*fac[8-i]; has[s[i]-'0']=1; } return res; } void bfs() { Eight now,next; queue<Eight> q; now.x=8; strcpy(now.s,"123456789"); q.push(now); vis[Find(now.s)]=1; while(!q.empty()) { now=q.front(); q.pop(); int pos1=Find(now.s); int x=now.x/3; int y=now.x%3; for(int i=0;i<4;i++) { next=now; int tx=x+dir[i][0]; int ty=y+dir[i][1]; if(tx>=0 && tx<=2 && ty>=0 && ty<=2) { next.x=tx*3+ty; swap(next.s[now.x],next.s[next.x]); int pos2=Find(next.s); if(!vis[pos2]) { vis[pos2]=1; pre[pos2]=pos1; way[pos2]=Dir[i]; q.push(next); } } } } } int main() { bfs(); char s[10]; while(scanf(" %c",&s[0])!=EOF) { for(int i=0;i<9;i++) { if(i) scanf(" %c",&s[i]); if(s[i]=='x') s[i]='9'; } int pos=Find(s); if(vis[pos]) { while(pos) { printf("%c",way[pos]); pos=pre[pos]; } printf(" "); } else printf("unsolvable "); } return 0; }
4、HDU 3567
Eight II
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 130000/65536 K (Java/Others)
Total Submission(s): 1243 Accepted Submission(s): 270
In this game, you are given a 3 by 3 board and 8 tiles. The tiles are numbered from 1 to 8 and each covers a grid. As you see, there is a blank grid which can be represented as an 'X'. Tiles in grids having a common edge with the blank grid can be moved into that blank grid. This operation leads to an exchange of 'X' with one tile.
We use the symbol 'r' to represent exchanging 'X' with the tile on its right side, and 'l' for the left side, 'u' for the one above it, 'd' for the one below it.
A state of the board can be represented by a string S using the rule showed below.
The problem is to operate an operation list of 'r', 'u', 'l', 'd' to turn the state of the board from state A to state B. You are required to find the result which meets the following constrains:
1. It is of minimum length among all possible solutions.
2. It is the lexicographically smallest one of all solutions of minimum length.
The input of each test case consists of two lines with state A occupying the first line and state B on the second line.
It is guaranteed that there is an available solution from state A to B.
The first line is in the format of "Case x: d", in which x is the case number counted from one, d is the minimum length of operation list you need to turn A to B.
S is the operation list meeting the constraints and it should be showed on the second line.
这个题和上一个一样,显然需要预处理,不过这个需要预处理9张表,由于起始位置都在变,所以建立映射
注意不要使用string,会MLE
还有注意字典序
1248MS
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <map> using namespace std; #define N 400000 struct Eight { int x; //x记录X的位置 char s[9]; }; bool vis[N]; int pre[10][N]; char way[10][N]; char Dir[]="dlru"; int dir[4][2]={1,0,0,-1,0,1,-1,0}; int fac[]={1,1,2,6,24,120,720,5040,40320,326880}; int Find(char s[]) { int i,j,k,res=0; bool has[10]={0}; for(i=0;i<9;i++) { for(k=0,j=1;j<s[i]-'0';j++) if(!has[j]) k++; res+=k*fac[8-i]; has[s[i]-'0']=1; } return res; } void bfs(int k) { Eight now,next; queue<Eight> q; memset(vis,0,sizeof(vis)); now.x=k-1; strcpy(now.s,"123456789"); q.push(now); vis[Find(now.s)]=1; while(!q.empty()) { now=q.front(); q.pop(); int pos1=Find(now.s); int x=now.x/3; int y=now.x%3; for(int i=0;i<4;i++) { next=now; int tx=x+dir[i][0]; int ty=y+dir[i][1]; if(tx>=0 && tx<=2 && ty>=0 && ty<=2) { next.x=tx*3+ty; swap(next.s[now.x],next.s[next.x]); int pos2=Find(next.s); if(!vis[pos2]) { vis[pos2]=1; pre[k][pos2]=pos1; way[k][pos2]=Dir[i]; q.push(next); } } } } } int main() { bfs(1); bfs(2); bfs(3); bfs(4); bfs(5); bfs(6); bfs(7); bfs(8); bfs(9); int k,i,T,iCase=1; char s1[10],s2[10]; scanf("%d",&T); while(T--) { scanf("%s%s",s1,s2); map<char,char> mp; for(i=0;i<9;i++) { if(s1[i]=='X') k=i+1; mp[s1[i]]=i+'1'; } for(i=0;i<9;i++) { s2[i]=mp[s2[i]]; } char ans[N],len=0; int pos=Find(s2); while(pos) { ans[len++]=way[k][pos]; pos=pre[k][pos]; } printf("Case %d: %d ",iCase++,len); for(i=len-1;i>=0;i--) cout<<ans[i]; printf(" "); } return 0; }