poj1184聪明的打字员(操作分离+bfs)

来源:互联网 发布:合肥淘宝包装招聘 编辑:程序博客网 时间:2024/05/16 08:30

->题目请戳这里<-

题目大意:给2个数字串,给6种操作,要求最少的步数将第一串变成第二串。6种操作分别是:

1:swap0:光标位置不变,将光标位置数字与第一个数字交换;

2:swap1:光标位置不变,将光标位置数字与第六个数字交换;

3:left:如果光标不在1位置,光标左移一位;

4:right:如果光标不在6位置,光标右移一位;

5:up:光标位置不变,如果光标位置数字小于9,光标位置数字加1,否则不变;

6:down:光标位置不变,如果光标位置数字大于0,光标位置数字减一,否则不变;

题目分析:求最少步数,bfs。这题昨天晚上开始写的,今天下午AC的,到刚才灵机一动才算解决了这个问题。一开始看完题满心欢喜的拍了个双向bfs,结果华丽丽的TLE了。。。显然没有估算状态数会达到6*1000000。但实际上这题可以证明59步内一定会出解的。因为6个操作中有2对互逆操作,所以搜索的过程中会产生大量的无用状态,导致超时。一开始不想重写,不断的加优化,直到代码改的面目全非才决定重写。其实6种操作可以分成2类:1-4操作是第一类,只能改变光标位置,5-6操作能改变光标位置的数。

所以我们将改变数值的操作和改变光标位置的操作分离开来,对改变光标位置的操作进行bfs,最后与结果比较,光标经过的位置可以改变大小,每一位的改变数值的操作次数为该状态与目标状态绝对值之和。这样就能避免每一步都扩展6个状态导致不断的up,down,产生大量重复状态。而光标是从1号位置不断向右移动的,所以光标的状态可以从2^6降到10。具体可以看->这个<-。不过写的过程中又是各种粗心,各种错误搞的好不蛋疼。下午的时候终于过了。但是心情还是很沉重,因为这题还是有bug,查了网上4-5份代码,都是有bug的,有的题解说左移操作是没用的,因此没有考虑也过了。其实是错的。swap操作其实有交换相邻2个数的功能,给的2个数字串第2位第3位分别是19和91,其余4位全部相同,那么直接交换这2位显然是最快的操作,操作过程为:right-->swap0-->right-->swap0-->left-->swap0。所以左移操作是必须的!!不过如果按照网上一般的操作分离的思路做这样的数据跑出来是错的,因为还是有重复的左移操作。但是poj的数据显然不够强,所以这样写的代码都能过。虽然过了,但心里还是不舒服。又分别用A*和IDA*写了一下,由于估价函数写的很挫,本地测试已严重超时。。。刚才灵机一动,想了一下,在AC的代码上改了一下,在每个状态里面加一个标记,记录是否向左走过,如果当前状态已经向左走过,那么以后他所扩展的状态就都不向左走了,因为向左走是必须的,但不能向左走太远,如果一个状态需要光标向左走2步,而光标是从左边过来的,那么光标在当前光标位置左边一位的时候已经有向左移一位的扩展了,所以没必要向左边移2位。

详情请见代码:

#include <iostream>#include<cstdio>#include<cstring>#include<cmath>#include<map>using namespace std;const int N = 100005;char s1[7],s2[7];int ans;bool flag[10][10][10][10][10][10][10];struct node{    char s[7];    char pos[7];    int step,cur;    bool left;}ss,now;struct que{    struct node t[N];    int head,tail;    void init()    {        head = tail = 0;    }    bool empty()    {        return head == tail;    }    struct node top()    {        return t[head];    }    void pop()    {        head ++ ;        if(head >= N)            head %= N;    }    void push(struct node a)    {        t[tail] = a;        tail ++;        if(tail >= N)            tail %= N;    }}q;int getstate(){    if(ss.pos[0]=='1'&&ss.pos[1]=='0'&&ss.pos[2]=='0'&&ss.pos[3]=='0'&&ss.pos[4]=='0'&&ss.pos[5]=='0')        return 0;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='0'&&ss.pos[3]=='0'&&ss.pos[4]=='0'&&ss.pos[5]=='0')        return 1;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='1'&&ss.pos[3]=='0'&&ss.pos[4]=='0'&&ss.pos[5]=='0')        return 2;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='1'&&ss.pos[3]=='1'&&ss.pos[4]=='0'&&ss.pos[5]=='0')        return 3;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='1'&&ss.pos[3]=='1'&&ss.pos[4]=='1'&&ss.pos[5]=='0')        return 4;    if(ss.pos[0]=='1'&&ss.pos[1]=='0'&&ss.pos[2]=='0'&&ss.pos[3]=='0'&&ss.pos[4]=='0'&&ss.pos[5]=='1')        return 5;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='0'&&ss.pos[3]=='0'&&ss.pos[4]=='0'&&ss.pos[5]=='1')        return 6;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='1'&&ss.pos[3]=='0'&&ss.pos[4]=='0'&&ss.pos[5]=='1')        return 7;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='1'&&ss.pos[3]=='1'&&ss.pos[4]=='0'&&ss.pos[5]=='1')        return 8;    if(ss.pos[0]=='1'&&ss.pos[1]=='1'&&ss.pos[2]=='1'&&ss.pos[3]=='1'&&ss.pos[4]=='1'&&ss.pos[5]=='1')        return 9;    return -1;}int getans(){    int ret = 0;    int i;    for(i = 0;i < 6;i ++)    {        if(now.pos[i] == '1')            ret += abs(now.s[i] - s2[i]);        else        {            if(now.s[i] != s2[i])                return 100000;        }    }    return ret + now.step;}int bfs(){    q.init();    memset(flag,0,sizeof(flag));    strcpy(ss.s,s1);    ans = 10000;    strcpy(ss.pos,"100000");    ss.cur = ss.step = 0;    ss.left = false;    flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][0] = 1;    q.push(ss);    while(!q.empty())    {        now = q.top();        if(now.step > ans)            break;        //printf("%s:%d  %d\n",now.s,now.cur,now.step);        //system("pause");        int ttt = getans();        if(ans > ttt)            ans = ttt;        q.pop();        if(now.cur)//left,swap0        {            ss = now;            ss.step ++;            int tp;            if(ss.left == false)            {                ss.pos[ss.cur] = '0';                ss.cur --;                ss.left = true;                ss.pos[ss.cur] = '1';                tp = getstate();                if(!flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp])                {                    flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp] = 1;                    q.push(ss);                }            }            ss = now;            ss.step ++;            tp = getstate();            char c = ss.s[0];            ss.s[0] = ss.s[ss.cur];            ss.s[ss.cur] = c;            if(!flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp])            {                flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp] = 1;                q.push(ss);            }        }        if(now.cur < 5)//right,swap1        {            ss = now;            ss.step ++;            ss.cur ++;            ss.pos[ss.cur] = '1';            int tp = getstate();            if(!flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp])            {                flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp] = 1;                q.push(ss);            }            ss = now;            ss.step ++;            ss.pos[5] = '1';            char c = ss.s[5];            ss.s[5] = ss.s[ss.cur];            ss.s[ss.cur] = c;            tp = getstate();            if(!flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp])            {                flag[ss.s[0] - '0'][ss.s[1] - '0'][ss.s[2] - '0'][ss.s[3] - '0'][ss.s[4] - '0'][ss.s[5] - '0'][tp] = 1;                q.push(ss);            }        }    }    return ans;}int main(){    //printf("ilovelcmss\n");    while(scanf("%s%s",s1,s2) != EOF)    {        printf("%d\n",bfs());    }    return 0;}//9980K32MS//9972K47MS/*123456 654321019000 091000654789 854841700638 815339000000 000000000000 111111000000 222222000000 333333000000 444444000000 555555000000 666666000000 777777000000 888888000000 999999*/

其实这题可以一次预处理就够了,我们bfs所要求的是起始状态到光标的10种状态加6!的全排列状态要多少步。然后执行up,down操作到达目标状态。

原创粉丝点击