• Eight (HDU


    The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:

    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.

    InputYou will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle

    1 2 3
    x 4 6
    7 5 8

    is described by this list:

    1 2 3 x 4 6 7 5 8
    OutputYou will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
    Sample Input

    2  3  4  1  5  x  7  6  8

    Sample Output

    ullddrurdllurdruldr

    题意:给出8个数和一个空位(x表示),空位可以向四个方向和数交换,求最小的操作方式试其变成 (1 2 3 4 5 6 7 8 x)
    思路:奇数码问题,先判断是否有解,因为是奇数码,所以有解的情况是两个情况的逆序对奇偶相同。
    另外,可以把x置换成9,然后对这个9位数进行标记,可以用map<int,int>,也可以用康托展开将其和自然数一一对应。
    A*的评估函数是每个位置到其应当位置的曼哈顿距离

    A* + map + string路径记录:
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<string.h>
    #include<map>
    using namespace std;
    
    struct Node
    {
        int cost,status;
        int s[10];
        int pos;
        int f;
        string ans;
        Node(int co=0,int st=0,int pos=0,int f=0,string ans=""):cost(co),status(st),pos(pos),f(f),ans(ans) {}
        bool operator <(const Node x)const
        {
            return cost > x.cost;
        }
    };
    map<int,int>mp;
    int ways[4][2] = {1,0,-1,0,0,1,0,-1};
    char WAYS[4] = {'d','u','r','l'};
    int ending;
    Node start;
    string ans;
    int Merge(int *a,int l,int r)
    {
        int mid = (r+l)>>1;
        int i=l,j=mid+1;
        int b[r-l+5];
        int cnt = 0;
        int k = 0;
        while(i <= mid && j <= r)
        {
            if(a[i] <= a[j])
            {
                b[cnt++] = a[i++];
            }
            else
            {
                b[cnt++] = a[j++];
                k += mid - i + 1;
            }
        }
        while(i <= mid)
            b[cnt++] = a[i++];
        while(j <= r)
            b[cnt++] = a[j++];
        for(int i=0; i<cnt; i++)
        {
            a[l++] = b[i];
        }
        return k;
    }
    
    void MER(int *a,int l,int r,int &cnt)
    {
        if(l >= r)
            return;
        int mid = (l+r)>>1;
        MER(a,l,mid,cnt);
        MER(a,mid+1,r,cnt);
        cnt += Merge(a,l,r);
    }
    
    int turn(int s[])
    {
        int cnt = 0;
        for(int i=1; i<=9; i++)
        {
            cnt *= 10;
            cnt += s[i];
        }
        return cnt;
    }
    
    int init(char word[])
    {
        int a[10];
        for(int i=2; i<=9; i++)
            scanf(" %c",&word[i]);
        int cnt = 0;
        for(int i=1; i<=9; i++)
            if((word[i]) != 'x')
                a[++cnt] = word[i]-'0';
        int num = 0;
        MER(a,1,cnt,num);
        ending = 0;
        for(int i=1; i<=9; i++)
        {
            ending *= 10;
            ending += i;
            if(word[i] == 'x')
                start.s[i] = 9,start.pos = i;
            else
                start.s[i] = word[i] - '0';
        }
        return (num & 1) == 1;
    }
    
    int cal(int s[])
    {
        int cnt = 0;
        for(int i=1; i<=9; i++)
        {
            if(s[i] == 9)
                continue;
            int x=(i-1)/3+1,y=(i-1)%3+1;
            int xx=(s[i]-1)/3+1,yy=(s[i]-1)%3+1;
            cnt += abs(x-xx)+abs(y-yy);
        }
        return cnt;
    }
    
    bool A_bfs(Node start)
    {
        priority_queue<Node>que;
        while(!que.empty())
            que.pop();
        start.status = turn(start.s);
        start.f = cal(start.s);
        start.cost  = start.f;
        que.push(start);
        while(!que.empty())
        {
            Node tmp = que.top();
            que.pop();
            int status = tmp.status;
            int cost = tmp.cost - tmp.f;
            if(mp[status])
                continue;
            mp[status] = 1;
            if(status == ending)
            {
                ans = tmp.ans;
                return 1;
            };
            int x = (tmp.pos-1)/3+1;
            int y = (tmp.pos-1)%3+1;
            for(int i=0; i<4; i++)
            {
                int xx = x+ways[i][0];
                int yy = y+ways[i][1];
                if(xx < 1 || xx > 3 || yy < 1 || yy > 3)
                    continue;
                Node t = tmp;
                t.s[(x-1)*3+y] = tmp.s[(xx-1)*3+yy];
                t.s[(xx-1)*3+yy] = 9;
                t.status = turn(t.s);
                t.f = cal(t.s);
                t.cost = cost+1+t.f;
                t.pos = (xx-1)*3+yy;
                t.ans += WAYS[i];
                que.push(t);
            }
    
        }
        return 0;
    }
    
    int main()
    {
        char word[10];
        while(~scanf(" %c",&word[1]))
        {
            mp.clear();
            if(init(word))
                printf("unsolvable
    ");
            else
            {
                A_bfs(start);
                cout << ans << endl;
            }
        }
    }
    View Code

    双向bfs+康拓展开+递归路径记录(注:路径记录不能都用递归,会ME,也许姿势不对,对于从终态搜索的,因为其本身就是倒序,可以采用递推,从当前状态推过去)

    #include<bits/stdc++.h>
    using namespace std;
    
    struct Node
    {
        int cost,status;
        int s[10];
        int pos;
        Node(int co=0,int st=0,int pos=0):cost(co),status(st),pos(pos){}
    };
    const int maxn = 4e5;
    int fac[9] = {1,1,2,6,24,120,720,5040,40320};
    int ways[4][2] = {1,0,-1,0,0,1,0,-1};
    char WAYS[4] = {'d','u','r','l'};
    char FWAYS[4]= {'u','d','l','r'};
    char path[maxn],path2[maxn];
    int pre[maxn],pre2[maxn];
    bool vis[2][maxn];
    int ans;
    queue<Node>que[2];
    Node start,ending;
    char word[10];
     int a[10],b[10];
    
    int cantor(int s[])
    {
        int sum = 0;
        for(int i=1; i<=9; i++)
        {
            int num = 0;
            for(int j=i+1; j<=9; j++)
            {
                if(s[j] < s[i])
                    num++;
            }
            sum += num*fac[9-i];
        }
        return sum+1;
    }
    
    int Merge(int *a,int l,int r)
    {
        int mid = (r+l)>>1;
        int i=l,j=mid+1;
        int cnt = 0;
        int k = 0;
        while(i <= mid && j <= r)
        {
            if(a[i] <= a[j])
            {
                b[cnt++] = a[i++];
            }
            else
            {
                b[cnt++] = a[j++];
                k += mid - i + 1;
            }
        }
        while(i <= mid)
            b[cnt++] = a[i++];
        while(j <= r)
            b[cnt++] = a[j++];
        for(int i=0; i<cnt; i++)
        {
            a[l++] = b[i];
        }
        return k;
    }
    
    void MER(int *a,int l,int r,int &cnt)
    {
        if(l >= r)
            return;
        int mid = (l+r)>>1;
        MER(a,l,mid,cnt);
        MER(a,mid+1,r,cnt);
        cnt += Merge(a,l,r);
    }
    
    int init(char word[])
    {
        memset(vis,0,sizeof(vis));
        for(int i=2; i<=9; i++)
            scanf(" %c",&word[i]);
        int cnt = 0;
        for(int i=1; i<=9; i++)
            if((word[i]) != 'x')
                a[++cnt] = word[i]-'0';
        int num = 0;
        MER(a,1,cnt,num);
        for(int i=1; i<=9; i++)
        {
            ending.s[i] = i;
            if(word[i] == 'x')
                start.s[i] = 9,start.pos = i;
            else
                start.s[i] = word[i] - '0';
        }
        start.status = cantor(start.s);
        ending.status = cantor(ending.s);
        ending.pos = 9;
        return (num & 1) == 1;
    }
    
    bool bfs(int w)
    {
        int num = que[w].size();
        while(num--)
        {
    
            Node tmp = que[w].front();
            que[w].pop();
            int status = tmp.status;
            int cost = tmp.cost;
            if(vis[w^1][status])
            {
                ans = status;
                return 1;
            }
            int x = (tmp.pos-1)/3+1;
            int y = (tmp.pos-1)%3+1;
            for(int i=0; i<4; i++)
            {
                int xx = x+ways[i][0];
                int yy = y+ways[i][1];
                if(xx < 1 || xx > 3 || yy < 1 || yy > 3 )
                    continue;
                Node t = tmp;
                t.s[(x-1)*3+y] = tmp.s[(xx-1)*3+yy];
                t.s[(xx-1)*3+yy] = 9;
                t.status = cantor(t.s);
                if(vis[w][t.status])continue;
                vis[w][t.status] = 1;
                t.s[(x-1)*3+y] = tmp.s[(xx-1)*3+yy];
                t.s[(xx-1)*3+yy] = 9;
                t.cost = cost+1;
                t.pos = (xx-1)*3+yy;
                if(w == 0)path[t.status] = WAYS[i],pre[t.status] = status;
                else path2[t.status] = FWAYS[i],pre2[t.status] = status;
                que[w].push(t);
            }
        }
        return 0;
    }
    
    void out(int w)
    {
        if(pre[w] == -1)
            return;
        out(pre[w]);
        printf("%c",path[w]);
    }
    void out2(int w)
    {
        while(pre2[w] != -1)
        {
            printf("%c",path2[w]);
            w = pre2[w];
        }
    }
    void solve()
    {
        while(!que[0].empty())que[0].pop();
        while(!que[1].empty())que[1].pop();
        que[0].push(start);
        que[1].push(ending);
        pre[start.status] = pre2[ending.status] = -1;
        vis[0][start.status] = vis[1][ending.status] = 1;
        while(!que[0].empty() || !que[1].empty())
        {
            if(bfs(0))
            {
                out(ans);
                out2(ans);
                puts("");
                return;
            }
            if(bfs(1))
            {
                out(ans);
                out2(ans);
                puts("");
                return;
            }
        }
    }
    
    int main()
    {
        while(~scanf(" %c",&word[1]))
        {
            if(init(word))
                printf("unsolvable
    ");
            else
            {
                solve();
            }
        }
    }
    View Code



  • 相关阅读:
    linux系统安装mysql数据库
    laypage分页控件使用方法
    could not get wglGetExtensionsStringARB
    Eclipse -- 自动补齐设置和其他用法
    Android开发--AndroidManifest.xml文件解析
    Java--常识
    课题论文写作时思路---目前存在的不足
    课题论文之调研---已有研究算法概述
    课题论文之调研---脏腑辨证
    Bayesian 网络分类算法
  • 原文地址:https://www.cnblogs.com/iwannabe/p/10617092.html
Copyright © 2020-2023  润新知