HDU 1043 / POJ 1077 Eight(八数码问题)

题目: HUD POJ  
这就是我们以前玩过的一种游戏,题目是3*3的格子有一个是空的,把他们还原成特定的顺序.
有人说没有做过这个题目的人生是不完整的?
 我写了一发纯暴力,map<string, int> 判重,map<string , string > 记录路径 竟然让我在HDU水过了,代码太挫了就不贴了。
其实可以发现 这样判重是非常耗时,而且 显然可以找到一个hash关系的,因为一共有9!种排列方式 ,如果能找到一种双射的话,无论是判重,还有记录路径都会优化很多的。
如果我们可以对于每一种排列求出它在所有排列中字典序排列中的位置,就可以找到双射了。
其实是有的------ 康托展开 
对于记录路径,可以记录当前的方向和上一步的状态,这样可以大大节省内存。
对于HDU 给了5s, 多组数据,可以打表,因为终态确定,可以从终态出发BFS,对于每组数据,就成了询问了。
对于POJ 1s,单组数据,  打表就没有了意义,可以按照他给的状态为起始状态BFS。

还有很多更优的解法吧,慢慢补上吧。

POJ: 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1000000000
#define N 400000
char ss[3];
int fac[11], dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
char dd[5] = {"rldu"}; 
struct node
{
    int num, zero, x[11];
};
node S, T;
bool vis[N];
vector<char > save; 
struct nn
{
    char th;
    int last;
}mm[N];
int cal(int x[])
{
    int ret = 0;
    for(int i = 1; i <= 9; i++) {
        int cou = 0;
        for(int j = i+1; j <= 9; j++) {
            if(x[j] < x[i]) cou++;
        }
        ret += cou * fac[9 - i ];
    }
    return ret;
}
int change(node &in, int dx, int dy)
{
    int x = (in.zero - 1) /3 + 1;
    int y = (in.zero - 1) %3 + 1;
    int nx = x + dx;
    int ny = y + dy;
    if(nx < 1 || nx > 3 || ny < 1 || ny > 3) return 0;
    int ww = (nx - 1) * 3 + ny;
    swap(in.x[in.zero], in.x[ww]);
    in.num = cal(in.x);
    in.zero = ww;
    return 1;
}
int bfs()
{
    queue<node > Q;
    Q.push(S);
    memset(vis, 0, sizeof(vis)); 
    vis[S.num] = 1;
    mm[S.num].last = -1;
    node now, next;
    while(!Q.empty()) {
        now = Q.front();  Q.pop();
        if(now.num == T.num) return 1;  
        for(int i = 0; i< 4; i++) {
            next = now;
            int tmp = change(next, dir[i][0], dir[i][1]);
            if(!tmp) continue;
            if(vis[next.num]) continue;
            vis[next.num ] = 1;
            mm[next.num].last = now.num;
            mm[next.num].th = dd[i];
            Q.push(next);
        }
    }
    return 0; 
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
    fac[0] = 1;
    for(int i = 1; i <= 10; i++) fac[i] = fac[i-1] * i;
    int s[11];
    for(int i = 1; i <= 9; i++) T.x[i] = i;
    T.zero = 9;
    T.num = cal(T.x);
	while(scanf("%s", ss) != EOF) {
        int tmp , zero ;
        if(ss[0] =='x') tmp = 9, zero = 1;
        else tmp = ss[0] - '0';
        S.x[1] = tmp;
        for(int i = 1; i <= 8; i++) {
            scanf("%s", ss);
            if(ss[0] == 'x') tmp = 9, zero = i+1;
            else tmp = ss[0] - '0';
            S.x[i+1] = tmp;
        }
        S.zero = zero; 
        S.num = cal(s);
        int ans = bfs(); 
        if(ans == 1) {
        	int gg = T.num; 
        	save.clear(); 
        	for(int tmp = gg; mm[tmp].last != -1; tmp = mm[tmp].last) save.push_back(mm[tmp].th);  
        	for(int i = save.size() -1 ; i >= 0; i--) printf("%c", save[i]); puts(""); 
        }
        else puts("unsolvable"); 
	}
	return 0;
}

HDU: 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define INF 1000000000
#define N 400000
char ss[3];
int fac[11], dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
char dd[5] = {"lrud"};
struct node
{
    int num, zero, x[11];
};
node S;
bool vis[N];
struct nn
{
    char th;
    int last;
}mm[N];
int cal(int x[])
{
    int ret = 0;
    for(int i = 1; i <= 9; i++) {
        int cou = 0;
        for(int j = i+1; j <= 9; j++) {
            if(x[j] < x[i]) cou++;
        }
        ret += cou * fac[9 - i ];
    }
    return ret;
}
int change(node &in, int dx, int dy)
{
    int x = (in.zero - 1) /3 + 1;
    int y = (in.zero - 1) %3 + 1;
    int nx = x + dx;
    int ny = y + dy;
    if(nx < 1 || nx > 3 || ny < 1 || ny > 3) return 0;
    int ww = (nx - 1) * 3 + ny;
    swap(in.x[in.zero], in.x[ww]);
    in.num = cal(in.x);
    in.zero = ww;
    return 1;
}
void bfs()
{
    queue<node > Q;
    Q.push(S);
    vis[S.num] = 1;
    mm[S.num].last = -1;
    node now, next;
    while(!Q.empty()) {
        now = Q.front(); Q.pop();
        for(int i = 0; i< 4; i++) {
            next = now;
            int tmp = change(next, dir[i][0], dir[i][1]);
            if(!tmp) continue;
            if(vis[next.num]) continue;
            vis[next.num ] = 1;
            mm[next.num].last = now.num;
            mm[next.num].th = dd[i];
            Q.push(next);
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
    fac[0] = 1;
    for(int i = 1; i <= 10; i++) fac[i] = fac[i-1] * i;
    int s[11];
    for(int i = 1; i <= 9; i++) S.x[i] = i;
    S.zero = 9;
    S.num = cal(S.x);
    bfs();
    while(scanf("%s", ss) != EOF) {
        int tmp ;
        if(ss[0] =='x') tmp = 9;
        else tmp = ss[0] - '0';
        s[1] = tmp;
        for(int i = 1; i <= 8; i++) {
            scanf("%s", ss);
            if(ss[0] == 'x') tmp = 9;
            else tmp = ss[0] - '0';
            s[i+1] = tmp;
        }
        int gg = cal(s);
        if(!vis[gg]) printf("unsolvable\n");
        else {
            for(int t = mm[gg].last, g = gg; t != -1; t = mm[t].last) {
                printf("%c", mm[gg].th);
                gg = t;
            }
            puts("");
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值