您的位置:首页 > 其它

hdu 1043(经典搜索)

2015-10-11 20:59 323 查看
题意:

给你一个初始的图,然后每次输入一个图,要求移动x最小的步数达到和初始图一样,输出路径

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->


好像有很多中方法解决这个问题:八数码的八个境界

①bfs +
康托展开+打表 /* 其他的还不会,有空去试试 - -

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std;

const int MAXN=362900;//最多是9!/2
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
//         0!1!2!3! 4! 5!  6!  7!   8!    9!
bool vis[MAXN];//标记
char path[MAXN][40];//记录路径
int cantor(int s[])//康拖展开求该序列的hash值
{
    int sum=0;
    for(int i=0; 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-1]);
    }
    return sum+1;
}

struct node
{
    int matri[10];
    int position;
    char path[50];
    int state;
};

queue<node>que;
char dire[5] = "dlur";
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};

void bfs()
{
    memset(vis,false,sizeof(vis));
    node cur;
    for(int i = 0; i < 8; i++)
        cur.matri[i] = i+1;
    cur.matri[8] = 0;
    cur.state = 46234;
    cur.path[0] = '\0';
    cur.position = 8;
    que.push(cur);
    vis[cur.state] = true;
    path[cur.state][0] = '\0';
    while(!que.empty())
    {
        cur = que.front();
        que.pop();
        int x = cur.position/3;
        int y = cur.position%3;

        for(int i = 0; i < 4; i++)
        {
            int tx = x + dir[i][0];
            int ty = y + dir[i][1];
            if(tx < 0 || tx > 2 || ty < 0 || ty > 2)
                continue;
            node t = cur;

            t.position =tx*3+ty;
            t.matri[cur.position] = t.matri[t.position];
            t.matri[t.position] = 0;
            t.state =cantor(t.matri);
            if(!vis[t.state])
            {
                path[t.state][0] = t.path[0] = dire[i];
                int len = strlen(cur.path);
                for(int j = 1;j <= len+1;j++)
                    path[t.state][j] = t.path[j] = cur.path[j-1];
                vis[t.state] = true;
                que.push(t);
            }
        }
    }
}

char ch;
int q[10];
int main()
{
    bfs();
    while(cin >> ch)
    {
        if(ch == 'x')
            q[0] = 0;
        else
            q[0] = ch-'0';
        for(int i = 1; i < 9; i++)
        {
            cin >> ch;
            if(ch == 'x')
                q[i] = 0;
            else
                q[i] = ch-'0';
        }
        int ans = cantor(q);
       // printf("%d\n",ans);
        if(!vis[ans])
            printf("unsolvable\n");
        else
        {
            cout <<path[ans]<<endl;
        }
    }
    return 0;
}


②双向bfs + 康拓展开+奇偶剪枝

剪枝:当x左右移动时,序列不变;上下移动时,移动2位后逆序数+2,所以奇偶性不变

双向bfs:因为扩展越大,你要搜索的部分就更多.而同时从开头和结果开始理论上来说会快很多

#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
typedef long long ll;
using namespace std;

const int MAXN=370000;
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880}; //康拖展开判重
//         0!1!2!3! 4! 5!  6!  7!   8!    9!
int  vis[MAXN];//标记
int  vis2[MAXN];
int cantor(string s)//康拖展开求该序列的hash值
{
    int sum=0;
    for(int i=0; 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-1]);
    }
    return sum+1;
}

struct node
{
    string path;
    int state;
} From;

struct node2
{
    int num;
    char ch;
} pre[MAXN];

char dire2[5] = "dlur";
char dire1[5] = "urdl";
int dir[4] = {-3,1,3,-1};

void pri(int t)
{
    if(pre[t].num == -1)
        return ;
    pri(pre[t].num);
    printf("%c",pre[t].ch);
}

void bfs(node cur)
{
    queue<node>que1;
    queue<node>que2;
    memset(vis,0,sizeof(vis));
    memset(vis2,0,sizeof(vis2));

    pre[0].num = pre[1].num  = pre[2].num = -1;
    node last,tp;
    vis[cantor(cur.path)] = 1;
    last.path ="123456780";
    last.state = 8;
    vis2[cantor(last.path)] = 2;
    que1.push(From);
    que2.push(last);
    int num = 2;

    while(!que1.empty() && !que2.empty())
    {
        //正向搜索
        cur = que1.front();
        que1.pop();
        int stat = cantor(cur.path);
        if(vis2[stat])
        {
            pri(vis[stat]);
            int k = vis2[stat];
            while(pre[k].num != -1)
            {
                printf("%c",pre[k].ch);
                k = pre[k].num;
            }
            printf("\n");
            return;
        }
        for(int i = 0; i < 4; i++)
        {
            if(i==0&&cur.state<3)continue;             //up
            if(i==1&&cur.state%3 == 2)continue;       //right
            if(i==2&&cur.state>5)continue;            //down
            if(i==3&&cur.state%3 == 0)continue;       //left
            int posi = cur.state + dir[i];
            tp = cur;
            swap(tp.path[cur.state],tp.path[posi]);
            int x = cantor(tp.path);
            if(vis[x])
                continue;
            vis[x] = ++num;

            tp.state = posi;
            pre[num].ch = dire1[i];
            pre[num].num = vis[stat];
            que1.push(tp);
        }

        //反向搜索
        last = que2.front();
        que2.pop();
        stat = cantor(last.path);
        if(vis[stat])
        {
            pri(vis[stat]);
            int k =vis2[stat];
            while(pre[k].num!=-1)
            {
                printf("%c",pre[k].ch);
                k=pre[k].num;
            }
            printf("\n");
            return ;
        }
        for(int i = 0; i < 4; i++)
        {
            if(i==0&&last.state<3)continue;
            if(i==1&&last.state%3==2)continue;
            if(i==2&&last.state>5)continue;
            if(i==3&&last.state%3==0)continue;
            int posi = last.state + dir[i];
            tp = last;
            swap(tp.path[last.state],tp.path[posi]);
            int x = cantor(tp.path);
            if(vis2[x])
                continue;
            vis2[x] = ++num;

            tp.state = posi;
            pre[num].ch = dire2[i];
            pre[num].num = vis2[stat];
            que2.push(tp);
        }
    }
    printf("unsolvable\n");
}

bool check(string a)
{
    int num = 0;
    for(int i = 0; i < 9; i++)
    {
        if(a[i] == '0' )
            continue;
        for(int j = i+1; j < 9; j++)
        {
            if(a[j] == '0') continue;
            if(a[j] < a[i])
                num++;
        }
    }
    if(num & 1)
        return true;
    else
        return false;
}

char ch;
char a[100];
int p[10];
int main()
{
    while(gets(a))
    {
        int tnum = 0;
        int n=strlen(a);
        From.path="";
        for(int i=0; i<n; i++)
            if(a[i]!=' ')
            {
                if(a[i]=='x')
                {
                    From.state=tnum;
                    From.path+='0';
                }
                else
                    From.path+=a[i];
                tnum++;
            }
        if(check(From.path))printf("unsolvable\n");
        else
              bfs(From);
    }
    return 0;
}


③A*算法+康拓展开+奇偶剪枝

它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。走到终点的代价为f
,主要由已经花费的代价g
和将要花费的代价h
决定,f

= g
+ h
,由于要找最短的路径,优先判定f
较小的。

而在本题中g
即是已经走过的步数,h
则是当前情况移动到-> 123456780的最小步数.

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
typedef long long ll;
using namespace std;

const int MAXN=362880;
int fac[]= {1,1,2,6,24,120,720,5040,40320,362880};
//         0!1!2!3! 4! 5!  6!  7!   8!    9!
int vis[MAXN];
int cantor(int s[])
{
    int sum=0;
    for(int i=0; i<9; i++)
    {
        int num=0;
        for(int j=0; j<i; j++)
            if(s[j]>s[i])num++;
        sum+=(num*fac[i]);
    }
    return sum;
}

struct node2
{
    int pre;
    char ch;
} pre[MAXN];

struct node
{
    int matri[10];
    int position;
    int have,to;
    int state;
    bool operator < (const node a)const
    {
        return have+to>a.have+a.to;
    }
};

char dire[5] = "urdl";
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};

int fx[]={2,0,0,0,1,1,1,2,2},fy[]={2,0,1,2,0,1,2,0,1};
int get_(node a)
{
    int ans = 0;
    for(int i = 0; i < 3; i++)
        for(int j = 0; j < 3; j++){
            if(a.matri[i*3+j]){
                ans+=abs(i-fx[a.matri[i*3+j]])+abs(j-fy[a.matri[i*3+j]]);
            }
        }
    return ans;
}
int fina[10];

void pri(int k)
{
    if(pre[k].pre == -1) return;
    pri(pre[k].pre);
    printf("%c",pre[k].ch);
}

void bfs(node cur)
{
    priority_queue<node>que;
    memset(vis,0,sizeof(vis));
    vis[cur.state] = 1;
    int tnum = 1;
    pre[1].pre = -1;
    for(int i = 0; i < 8; i++)
        fina[i] = i+1;
    fina[8] = 0;
    int _ans = cantor(fina);
    cur.have = 0;
    que.push(cur);
    while(!que.empty())
    {
        cur = que.top();
        que.pop();
        int x = cur.position/3;
        int y = cur.position%3;
        int num = cur.state;
        if(num == _ans)
        {
            int k = vis[num];
            pri(k);
            printf("\n");
            return ;
        }
        for(int i = 0; i < 4; i++)
        {
            int tx = x + dir[i][0];
            int ty = y + dir[i][1];
            if(tx < 0 || tx > 2 || ty < 0 || ty > 2)
                continue;
            node t = cur;

            t.position =tx*3+ty;
            t.matri[cur.position] = t.matri[t.position];
            t.matri[t.position] = 0;
            t.have++;
            t.to = get_(t);
            t.state =cantor(t.matri);
            if(!vis[t.state])
            {
                vis[t.state] = ++tnum;
                pre[tnum].pre = vis[num];
                pre[tnum].ch = dire[i];
                que.push(t);
            }
        }
    }
    printf("unsolvable\n");
}

bool check(int a[])
{
    int num = 0;
    for(int i = 0; i < 9; i++)
    {
        if(a[i] == 0 )
            continue;
        for(int j = i+1; j < 9; j++)
        {
            if(a[j] == 0) continue;
            if(a[j] < a[i])
                num++;
        }
    }
    if(num & 1)
        return true;
    else
        return false;
}

char ch;
int main()
{
    while(cin >> ch)
    {
        node from;
        if(ch == 'x')
        {
            from.matri[0] = 0;
            from.position = 0;
        }
        else
            from.matri[0] = ch-'0';
        for(int i = 1; i < 9; i++)
        {
            cin >> ch;
            if(ch == 'x')
            {
                from.matri[i] = 0;
                from.position = i;
            }
            else
                from.matri[i] = ch-'0';
        }
        int ans = cantor(from.matri);
        from.state = ans;
        // printf("%d\n",ans);
        if(check(from.matri))
            printf("unsolvable\n");
        else
            bfs(from);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: