UVa 12569

来源:互联网 发布:淘宝助手 编辑:程序博客网 时间:2024/05/17 01:30

问题

一棵4<=n<=15个节点的数。其中一个节点上一个机器人 还有些节点有石头, 指定机器人的起点和终点、以及石头的起始位置,求机器人最终到达终点最小步数的方案, 多解时输出一个即可. 每次机器人或者石头只能移动到相邻的空节点上。
eg: 有8个节点1\2\3\4\5\6\7\8
从1 能到达 2\6\7
从2 能到达 1\3\8
从3 能到达 2\4
从4 能到达 3\5

开始2\3\4节点上有石头
机器人的起始为1 终点为5

则至少16步 路径如下:
机器人 1-6
石头 2-1-7
机器人 6-1-2-8
石头 3-2-1-6
石头 4-3-2-1
机器人8-2-3-4-5

思路

  • 保证最短路径--IDA*算法
  • 保存每一步的状态 以及到达此状态时的一些信息
    用一个bit表示一个节点的状态[是否被占用] 最多有2^N个状态 每个状态中机器人的位置最多有N个;所以用二维数组存储,值是一个结构体;
struct stauts{    // 到达此状态用的步数    int cost;       // 对上一个状态pI 操作第a个bit=0 and 第b个bit=1     // 即移动机器人或者石头从a 节点到b节点后 达当前状态    short a, b;       // 上一个状态和上一个机器人的状态    int pI, prI;  } S[1<<N][N];

测试案例 & 结果

第一行是节点个数 接下来是节点关系 接下来2 3 4 是石头的位置 接下来是1 5 机器人的起点和终点; 0表示结束;86 11 71 22 32 83 44 50 02 3 4 01 5结果:机器人 1 6 石头 2 1 7 机器人 6 1 2 8 石头 3 2 1 6 石头 4 3 2 1 机器人 8 2 3 4 5 

代码

#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 15int G[N][N];        // storage edge linkint beginI, endI;   //机器人的起点和终点int S0, SN=-1;      //初态 和 终态int depthMax, depth;//当前允许的最大递归深度 当前深度struct stauts{    // 到达此状态用的步数    int cost;    // 对上一个状态pI 操作第a个bit=0 and 第b个bit=1    // 即移动机器人或者石头从a 节点到b节点后 达当前状态    short a, b;    // 上一个状态和上一个机器人的状态    int pI, prI;};struct stauts S[1<<N][N];// 递归寻找int DFS(int s, int rI){    struct stauts *st=&S[s][rI];    //printf("depth[%d][%d] s[%d] pas[%d] cost[%d] %d->%d robot[%d][%d][%d]\n",    //      depthMax, depth, s, st->pI, st->cost, st->a, st->b, st->prI, rI, endI);    //ppp(&s, 32);    if(depth > depthMax) return 0;    // 机器人到达终点    if( rI == endI )    {        if ( SN==-1 || S[SN][endI].cost > S[s][endI].cost )            SN = s;    }    // reached next status    int i,j,u,v,sNew, rINew, sN;    //遍历所有的节点    for(u=0; u<N; u++)    {        //如果节点u被占用 上面有一个石头或者机器人        if(s&1<<u)        {            // 遍历其余的节点 寻找能从u节点 移动到的&&还能被占用的节点v            for(v=0; v<N; v++)if(G[u][v] && !(s&1<<v))            {                //获取转移后的状态sNew                sNew=(s&(~(1<<u)))|(1<<v);                //获取转移后的状态中机器人的状态rINew                if(u==rI) rINew = v;                else rINew = rI;                //如果转移后的状态 还没被访问过 或者 访问过但步数太多;更新数据                if( S[sNew][rINew].cost==-1 || S[sNew][rINew].cost > st->cost+1 )                {                    S[sNew][rINew].a=u;                    S[sNew][rINew].b=v;                    S[sNew][rINew].pI=s;                    S[sNew][rINew].prI=rI;                    S[sNew][rINew].cost = st->cost+1;                    depth++;                    DFS(sNew, rINew);                    depth--;                }            }        }    }    return 0;}int test12569(){    int i,j,k,u,v,m,n,s;    scanf("%d", &n);    // 获取边的关系    memset(G, 0x00, sizeof(G));    while(scanf("%d %d", &u, &v)==2)    {        if(u==0&&v==0)break;        G[u-1][v-1]=G[v-1][u-1]=1;    }    //获取初始状态S0    S0 = 0;    while(scanf("%d", &u)==1)    {        if(u==0)break;        S0 |= (1<<(u-1));    }    scanf("%d %d", &beginI, &endI);    beginI--;    endI--;    S0 |= 1<<beginI;    for( depthMax=0; SN==-1 && depthMax < 80; depthMax++)    {            memset(S, -1, sizeof(S));            S[S0][beginI].cost=0;            DFS(S0, beginI);    }    // 打印路径    int ansI;    int ans[1000];    struct stauts *st;    if(SN==-1)    {        printf("cann't reached\n");    }    else    {        memset(ans, -1, sizeof(ans));        ansI=-1;        int lastA=-1, lastB=-1;        //倒序遍历路径 秉把路径 存储到ans中        st = &S[SN][endI];        while( st->pI != -1 )        {            if (st->b==lastA)            {                ans[++ansI]=lastA=st->a;            }            else            {                ++ansI;                ans[++ansI]=st->b;                ans[++ansI]=lastA=st->a;            }            // printf("%d %d\n", st->a , st->b);            st = &S[st->pI][st->prI];        }        //输出答案        v=beginI; k=0;        while( ansI>=0 )        {            //k==1机器人走 k==0石头走            if(ans[ansI]==v) k=1;            else k=0;            if(k==1) printf("机器人 ");            else printf("石头 ");            while(ansI!=-1 && ans[ansI]!= -1 )            {                if ( k==1 ) v=ans[ansI];                printf("%d ", ans[ansI--]+1);            }            ansI--;            printf("\n");        }    }}