八数码[POJ1077]、[LuoguP1379]、[caioj1046]

版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89435719

欢迎大家访问我的老师的OJ———caioj.cn

题目描述

作为经典的八数码问题
我就不描述题面了吧。

思路

普通的八数码就是宽搜嘛,我就不讲了。(我实在太懒了)
于是乎,我开始使用 A A* 乱搞。
关于 A A* ,详参 K K 短路
我们这里设估价函数 f f 为当前状态每一个数到目标状态每一个数的曼哈顿距离之和。
因为我们至少要 f / 2 f/2 的步数才能到达目标状态。
所以就好啦。
顺便用康托展开,加速一下。
POJ1077

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<cstdlib>
using namespace std;
const int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
const char A[4]={'l','r','u','d'};
int d[10];
inline void pre(){d[0]=1;for(int i=1;i<=8;i++)d[i]=d[i-1]*i;}
struct node
{
	int f,dis,x,y,k,a[4][4];
	string ans;
	node(){ans="";memset(a,0,sizeof(a));}
	bool operator <(const node a)const{return f==a.f?dis>a.dis:f>a.f;}
	inline int myabs(int x){return x<0?-x:x;}
	inline void kt()
	{
		k=0;
        int b[20],len=0;
        for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)b[++len]=a[i][j]+1;//相当于将一个3*3的图排成一行; 
        bool bo[20];memset(bo,false,sizeof(bo));//初始化 
        //统计当前这个是第几个康托排列 
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<b[i];j++)
            {
                if(bo[j]==false)
                {
                    k+=d[9-i];//9-i==0时,不会执行这一句 
                }
            }
            bo[b[i]]=true;
        } 
	}
	inline void get(const node &ed)
	{
		f=dis;int x1=1,y1=1;bool ap[10];memset(ap,false,sizeof(ap));
		while(x1<3)
		{
			if(y1==4)x1++,y1=1;
			bool bk=false;
			for(int i=1;i<=3;i++)
			{
				for(int j=1;j<=3;j++)
				{
					if(ap[a[i][j]])continue;
					if(a[i][j]==ed.a[x1][y1])
					{
						ap[a[i][j]]=true;
						f+=myabs(i-x1)+myabs(j-y1);
						y1++;bk=true;break;
					}
				}
				if(bk==true)break;
			}
		}
	}
};
bool vis[500010];
int main()
{
	pre();
	node st,ed;
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			char s[3];scanf("%s",s+1);
			if(s[1]=='x')st.x=i,st.y=j;
			else st.a[i][j]=s[1]-'0';
		}
	}
	st.kt();
	ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;
	ed.a[2][1]=4;ed.a[2][2]=5;ed.a[2][3]=6;
	ed.a[3][1]=7;ed.a[3][2]=8;ed.x=3,ed.y=3;
	ed.kt();
	priority_queue<node>q;
	q.push(st);
	while(!q.empty())
	{
		node t=q.top();q.pop();
		for(int i=0;i<4;i++)
		{
			node nxt=t;
			nxt.x+=dx[i];nxt.y+=dy[i];
			int x=nxt.x,y=nxt.y;
			if(x<1||x>3||y<1||y>3)continue;
			int tw=nxt.a[t.x][t.y];nxt.a[t.x][t.y]=nxt.a[x][y];nxt.a[x][y]=tw;
			nxt.kt();
			if(vis[nxt.k])continue;
			nxt.dis++;nxt.get(ed);nxt.ans+=A[i];vis[nxt.k]=true;
			if(nxt.k==ed.k){cout<<nxt.ans<<endl;return 0;}
			q.push(nxt);
		}
	}
	puts("unsolvable");
	return 0;
}

LuoguP1379

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int dx[4]={0,1,-1,0};
const int dy[4]={1,0,0,-1};
int d[9];
void pre()
{
    d[0]=1;for(int i=1;i<=8;i++)d[i]=d[i-1]*i;
}
struct node
{
    int dis,f,k,x,y,ans;
    int a[5][5];
    node(){dis=k=f=0;memset(a,0,sizeof(a));x=y=0;}
    bool operator <(const node &a)const{return f==a.f?dis>a.dis:f>a.f;}//重构小根堆 
    inline void kt()//康托展开 
    { 
        k=0;
        int b[20],len=0;
        for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)b[++len]=a[i][j]+1;//相当于将一个3*3的图排成一行; 
        bool bo[20];memset(bo,false,sizeof(bo));//初始化 
        //统计当前这个是第几个康托排列 
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<b[i];j++)
            {
                if(bo[j]==false)
                {
                    k+=d[9-i];
                }
            }
            bo[b[i]]=true;
        } 
    }
    inline void find_f(const node &ed)//A*的估计函数f 
    {
        int x1=1,y1=1;bool ap[10];memset(ap,false,sizeof(ap));
        f=dis;
        while(x1<=3)
        {
            if(y1==4)x1++,y1=1;
            bool bk=true;
            for(int i=1;i<=3;i++)
            {
                for(int j=1;j<=3;j++)
                {
                    if(ap[ed.a[i][j]])continue;
                    if(ed.a[i][j]==a[x1][y1])
                    {
                        f+=abs(x1-i)+abs(y1-j);ap[a[x1][y1]]=true;
                        y1++;
                        bk=false;
                        break;
                    }
                }
                if(bk==false)break;
            }
        }
    }
};
node st,ed;
priority_queue<node>q;
bool v[510000];
int main()
{
    pre();
    memset(v,false,sizeof(v));
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
        	char c=getchar();
            st.a[i][j]=c-'0';if(st.a[i][j]==0){st.x=i,st.y=j;}
        }
    }
    ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;
	ed.a[2][1]=8;ed.a[2][2]=0;ed.a[2][3]=4;
	ed.a[3][1]=7;ed.a[3][2]=6;ed.a[3][3]=5;
	ed.x=2,ed.y=2;
    st.kt();ed.kt();
    if(st.k==ed.k){printf("0\n");return 0;}
	v[st.k]=true;st.dis=0;st.find_f(ed);
    q.push(st);
    while(!q.empty())
    {
        node t=q.top();
        q.pop(); 
        for(int i=0;i<4;i++)
        {
            node now=t;
			int x=now.x+dx[i],y=now.y+dy[i];
            if(x<1||x>3||y<1||y>3)continue;
            int tw=now.a[now.x][now.y];now.a[now.x][now.y]=now.a[x][y];now.a[x][y]=tw;
            now.x=x,now.y=y;
            now.dis++;
            now.kt();
            if(v[now.k])continue;
            now.find_f(ed);
            v[now.k]=true;
			if(now.k==ed.k){printf("%d\n",now.dis);return 0;}
            q.push(now);
        }
    }
    return 0;
}

caioj1046(数据贼水)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int dx[4]={0,-1,0,1};
const int dy[4]={-1,0,1,0};
int d[9];
void pre()
{
    d[0]=1;for(int i=1;i<=8;i++)d[i]=d[i-1]*i;
}
struct node
{
    int dis,f,k,x,y;
    int a[5][5];
    node(){dis=k=f=0;memset(a,0,sizeof(a));x=y=0;}
    bool operator <(const node &a)const{return f==a.f?dis>a.dis:f>a.f;}
    inline void kt()
    { 
        k=0;
        int b[20],len=0;
        for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)b[++len]=a[i][j]+1;//相当于将一个3*3的图排成一行; 
        bool bo[20];memset(bo,false,sizeof(bo));//初始化 
        //统计当前这个是第几个康托排列 
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<b[i];j++)
            {
                if(bo[j]==false)
                {
                    k+=d[9-i];
                }
            }
            bo[b[i]]=true;
        } 
    }
    inline void find_f(const node &ed)
    {
        int x1=1,y1=1;bool ap[10];memset(ap,false,sizeof(ap));
        f=dis;
        while(x1<=3)
        {
            if(y1==4)x1++,y1=1;
            bool bk=true;
            for(int i=1;i<=3;i++)
            {
                for(int j=1;j<=3;j++)
                {
                    if(ap[ed.a[i][j]])continue;
                    if(ed.a[i][j]==a[x1][y1])
                    {
                        f+=abs(x1-i)+abs(y1-j);ap[a[x1][y1]]=true;
                        y1++;
                        bk=false;
                        break;
                    }
                }
                if(bk==false)break;
            }
        }
    }
     
};
node st,ed;
priority_queue<node>q;
bool v[1100000];
int main()
{
    pre();
    memset(v,false,sizeof(v));
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            scanf("%d",&st.a[i][j]);
            if(st.a[i][j]==0){st.x=i,st.y=j;}
        }
    }
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            scanf("%d",&ed.a[i][j]);
            if(ed.a[i][j]==0){ed.x=i,ed.y=j;}
        }
    }
    st.kt();ed.kt();v[st.k]=true;
    st.dis=1;
    st.find_f(ed);
    q.push(st);
    while(!q.empty())
    {
        node t=q.top();
        q.pop();
        for(int i=0;i<4;i++)
        {
            node now=t;
            int x=now.x+dx[i],y=now.y+dy[i];
            if(x<1||x>3||y<1||y>3)continue;
            int tw=now.a[now.x][now.y];now.a[now.x][now.y]=now.a[x][y];now.a[x][y]=tw;
            now.x=x,now.y=y;
            now.dis++;
            now.kt();
            if(v[now.k])continue;
            now.find_f(ed);
            v[now.k]=true;
            q.push(now);
            if(now.k==ed.k){printf("%d\n",now.dis);return 0;}
        }
    }
    return 0;
}

另外提供一种 IDA* \operatorname{IDA*} 做法:POJ貌似跑得比较慢。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<cstdlib>
using namespace std;
const int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
const char A[4]={'l','r','u','d'};
int d[10];
int dep;
inline void pre(){d[0]=1;for(int i=1;i<=8;i++)d[i]=d[i-1]*i;}
struct node
{
	int f,dis,x,y,k,a[4][4];
	string ans;
	node(){ans="";memset(a,0,sizeof(a));}
	inline int myabs(int x){return x<0?-x:x;}
	inline void kt()
	{
		k=0;
        int b[20],len=0;
        for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)b[++len]=a[i][j]+1;//相当于将一个3*3的图排成一行; 
        bool bo[20];memset(bo,false,sizeof(bo));//初始化 
        //统计当前这个是第几个康托排列 
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<b[i];j++)
            {
                if(bo[j]==false)
                {
                    k+=d[9-i];//9-i==0时,不会执行这一句 
                }
            }
            bo[b[i]]=true;
        } 
	}
	inline void get(const node &ed)
	{
		f=dis;int x1=1,y1=1;bool ap[10];memset(ap,false,sizeof(ap));
		while(x1<3)
		{
			if(y1==4)x1++,y1=1;
			bool bk=false;
			for(int i=1;i<=3;i++)
			{
				for(int j=1;j<=3;j++)
				{
					if(ap[a[i][j]])continue;
					if(a[i][j]==ed.a[x1][y1])
					{
						ap[a[i][j]]=true;
						f+=myabs(i-x1)+myabs(j-y1);
						y1++;bk=true;break;
					}
				}
				if(bk==true)break;
			}
		}
	}
};
node st,ed;
bool vis[500010];
bool dfs(node t)
{
	if(t.k==ed.k)
	{
		cout<<t.ans<<endl;
		return 1;
	}
	if(t.f>dep)return 0;
	for(int i=0;i<4;i++)
	{
		node nxt=t;
		nxt.x+=dx[i];nxt.y+=dy[i];
		int x=nxt.x,y=nxt.y;
		if(x<1||x>3||y<1||y>3)continue;
		int tw=nxt.a[t.x][t.y];nxt.a[t.x][t.y]=nxt.a[x][y];nxt.a[x][y]=tw;
		nxt.kt();if(vis[nxt.k])continue;
		nxt.dis++;nxt.get(ed);nxt.ans+=A[i];vis[nxt.k]=true;
		if(dfs(nxt))return 1;
		vis[nxt.k]=false;
	}
	return 0;
}
int main()
{
	pre();
	for(int i=1;i<=3;i++)
	{
		for(int j=1;j<=3;j++)
		{
			char s[3];scanf("%s",s+1);
			if(s[1]=='x')st.x=i,st.y=j;
			else st.a[i][j]=s[1]-'0';
		}
	}
	st.kt();
	ed.a[1][1]=1;ed.a[1][2]=2;ed.a[1][3]=3;
	ed.a[2][1]=4;ed.a[2][2]=5;ed.a[2][3]=6;
	ed.a[3][1]=7;ed.a[3][2]=8;ed.x=3,ed.y=3;
	ed.kt();
	dep=0;
	while(1&&dep<=30)
	{
		if(dfs(st))return 0;
		dep++;
	}
	puts("unsolvable");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/89435719