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"); } }}
阅读全文
0 0
- UVa 12569
- UVA 12569 Moving Pegs
- uva
- UVA
- UVA
- UVA
- uva
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- UVA
- EJBCA安装打印信息2
- 微信朋友圈广告开发
- 求一个整数数组的最大元素,用递归方法实现
- HTML (Hyper Text Markup Language) 常用标签 H
- Linux内核的并发与同步
- UVa 12569
- 图像识别之目标物体坐标确定(9月3日临时笔记)
- JAVA中的权限修饰符
- PAC成本方法
- Java实现二叉查找树的创建、查找、插入、删除、遍历
- 互联网产品用户体验的层次详解
- Spring bean提供了3中注入方式
- Windows Server 2016正式版教程:安装、激活、设置
- 通过JDBC访问数据库的基本步骤