UVa Problem 704 Colour Hash (色彩缤纷游戏)

//版权所有(C)2015 何伟亮

//本题若直接采用正向搜索会搜索16层的深度 由于深度太深搜索的元素太多会导致速度大为降低,所以我采用正向搜索和反向搜索相结合的方式
//先反向搜索9层的深度并将所有可能出现的情况放入cache中 然后正向搜索8层的深度如果在搜索的过程中发现结果已经在cache中则说明是可以
//在16步之内找到通往目标序列的方法,否则则无法找到.
#include <iostream>
#include <map>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <string>
#define LEFTCLOCK 1
#define RIGHTCLOCK 2
#define LEFTCOUNTERCLOCK 3
#define RIGHTCOUNTERCLOCK 4
#define RESERVEDEPTH 8//反向搜索的深度
using namespace std;
#define HALF 9 //左右两边滑块的数目
#define MIDDLE 3 //中间滑块的数目
#define NWHEEL 24;//总共滑块的数目
string target = "034305650078709T90121";//目标序列 034305650为左侧的顺时针序列 078709T90为右侧的逆时针序列 121为中间的序列 T代表10
int myreverse[4]={3,4,1,2};
struct node//用来存储节点当前的状态
{
    string config;//当前的状态
    string seq;//到达这个状态所经过的旋转序列
};
map <string,string> cache;//用来存储反向搜索出的所有结果
void rotate(string &a,int direction)//将字符序列进行旋转
{
    string oldleft,oldright,oldmiddle,newleft,newright,newmiddle;
    oldleft=a.substr(0,HALF);
    oldright=a.substr(HALF,HALF);
    oldmiddle=a.substr(2*HALF ,MIDDLE);
    switch(direction)
    {
    case LEFTCLOCK:
        newleft=oldmiddle.substr(1,2)+oldleft.substr(0,HALF-2);
        newright=oldright;
        newmiddle=oldleft.substr(HALF-2)+oldmiddle.substr(0,1);
        break;
    case RIGHTCLOCK:
        newleft=oldleft;
        newright=oldright.substr(2,HALF-2)+oldmiddle.substr(0,2);
        newmiddle=oldmiddle.substr(2)+oldright.substr(0,2);
        break;
    case LEFTCOUNTERCLOCK:
        newleft=oldleft.substr(2)+oldmiddle.substr(0,2);
        newright=oldright;
        newmiddle=oldmiddle.substr(2)+oldleft.substr(0,2);
        break;
    case RIGHTCOUNTERCLOCK:
        newleft=oldleft;
        newright=oldmiddle.substr(1,2)+oldright.substr(0,HALF-2);
        newmiddle=oldright.substr(HALF-2)+oldmiddle.substr(0,1);
        break;
    }
    a=newleft+newright+newmiddle;
}
void reversesearch(string goal)//进行反向搜索并将搜索的内容存放到cache中
{
    struct node a,temp;
    a.config=goal;
    a.seq="";
    queue <struct node> q;
    q.push(a);
    while(!q.empty())
    {
        temp=q.front();
        q.pop();
        if(temp.seq.length()>=RESERVEDEPTH)//如果深度超过了则停止
            continue;
        for(int i=LEFTCLOCK;i<=RIGHTCOUNTERCLOCK;i++)
        {
                if(temp.seq.length()>0)
                {
                    int nowreverse=myreverse[i-1];//得到当前方向的逆方向
                    int lastdirection=temp.seq[0];//上次的方向
                    if(nowreverse!=lastdirection&&(nowreverse+lastdirection==4||nowreverse+lastdirection==6))//当前的方向和上次的方向如果正好相反则跳过当前方向
                        continue;
                }
                string nowconfig=temp.config;//状态
                string nowseq=temp.seq;//序列
                rotate(nowconfig,i);//进行旋转
                if(cache.find(nowconfig)==cache.end())//在缓存中没有发现此状态
                {
                    struct node succeed;
                    succeed.config=nowconfig;
                    succeed.seq=char(myreverse[i-1]+'0')+nowseq;
                    q.push(succeed);
                    cache.insert(pair<string,string>(nowconfig,succeed.seq));
                }
        }
    }

}
bool mysearch(string origial)
{
    reversesearch(target);//计算出缓存
    queue<struct node> q;
    struct node a,temp;
    a.config=origial;
    a.seq="";
    q.push(a);
    while(!q.empty())
    {
        temp=q.front();
        q.pop();
        if(cache.find(temp.config)!=cache.end())//在缓存中找到相应的状态
        {
            cout<<temp.seq<<cache.find(temp.config)->second<<endl;
            return true;

        }
        if(temp.seq.length()>=RESERVEDEPTH+1)//超过了深度则跳过当前的检测节点
            continue;
        for(int i=LEFTCLOCK;i<=RIGHTCOUNTERCLOCK;i++)
        {
            if(temp.seq.length()>0)//检测当前的旋转方向是否和上次的旋转反向相反 相反则测试下一个旋转方向
            {
                int lastdirection=temp.seq[temp.seq.length()-1];//得到上次的旋转方向
                if(lastdirection!=i&&(lastdirection+i==4||lastdirection+i==6))//检测是否相反
                    continue;
            }
            string newconfig=temp.config;
            string newseq=temp.seq;
            rotate(newconfig,i);//进行相应的旋转
            struct node succeed;
            succeed.config=newconfig;
            succeed.seq=newseq+char(i+'0');
            q.push(succeed);//插入队列的尾部
        }
    }
    return false;
}
bool solved(string a)
{
    for(int i=0;i<target.length();i++)
        if(target[i]!=a[i])
        return false;
    return true;
}
int main()
{
    int n,c;
    cin>>n;
    string oldinput,newinput;
    while(n--)
    {
        oldinput.clear();
        int i=NWHEEL;
            while(i--)
                {
                    cin >> c;
                    if (c == 10)
                        oldinput.append(1, 'T');
                    else
                        oldinput.append(1, c + '0');
                }

        newinput=oldinput.substr(0,HALF)+oldinput.substr(HALF+MIDDLE,HALF)+oldinput.substr(2*HALF+MIDDLE);
        if(solved(newinput))
            cout<<"PUZZLE ALREADY SOLVED"<<endl;
        else
        {
            if(!mysearch(newinput))
                cout<<"NO SOLUTION WAS FOUND IN 16 STEPS"<<endl;
        }


    }

}

你可能感兴趣的:(回溯法)