zoukankan      html  css  js  c++  java
  • 阿里巴巴实习笔试:摸金校尉

    原题是:

    一个摸金校尉要通过一个矩形墓室,入口的位置为(0,0),出口的位置为(m,n)。墓室中散布着一些激光发射器,某些激光发射器之间有激光。m,n和激光的起始和终止位置(x1,y1,x2,y2)均为整数。请问他能否不碰到激光,成功通过墓室。

    思路:与激光器相碰就是激光器所在的线段与摸金校尉走的下一步的线段相交;在每一个点处,都有上下左右四个可行的方向,所以只要写一个深搜递归就可以找到一条通向出口的路径,下面附上代码,因为是直接在网页上面写的,没有编译过,所以可能存在错误,欢迎交流

    #include<iostream>
    #include<vector> using namespace std; int m , n ; //出口位置 int num; //墓室里面激光线段的个数; struct point { double x,y; }; struct segment { point begin,end; }; double min(double x,double y) { return x<y?x:y; } double max(double x,double y) { return x>y?x:y; } bool onsegment(point pi,point pj,point pk) //判断点pk是否在线段pi pj上 { if(min(pi.x,pj.x)<=pk.x&&pk.x<=max(pi.x,pj.x)) { if(min(pi.y,pj.y)<=pk.y&&pk.y<=max(pi.y,pj.y)) { return true; } } return false; } double direction(point pi,point pj,point pk) //计算向量pkpi和向量pjpi的叉积 { return (pi.x-pk.x)*(pi.y-pj.y)-(pi.y-pk.y)*(pi.x-pj.x); } bool judge(point p1,point p2,point p3,point p4) //判断线段p1p2和p3p4是否相交,相交的话就代表沿当前方向会与激光器触碰,返回true { double d1 = direction(p3,p4,p1); double d2 = direction(p3,p4,p2); double d3 = direction(p1,p2,p3); double d4 = direction(p1,p2,p4); if(d1*d2<0&&d3*d4<0) return true; if(d1==0&&onsegment(p3,p4,p1)) return true; if(d2==0&&onsegment(p3,p4,p2)) return true; if(d3==0&&onsegment(p1,p2,p3)) return true; if(d4==0&&onsegment(p1,p2,p4)) return true; return false; } /*在每一个节点处都有四个可能的方向,上下左右,如果当前没有找到解,并且上下左右任一方向的下一个点没有经历的话,就进行搜索,直到搜索到一个解为止*/ bool findways( int x , int y , vector<vector<bool> > &isthrough ){ // 递归找路径 bool ret = false; isthrough[x][y] = true; //标记当前点已经历 if( x == m && y == n ) //如果到达终点的话返回true return true; else{ //在每一个点有上下左右四个方向可以走 point start ; //记录当前点的位置 start.x = x; start.y = y; if( y + 1 <= n && isthrough[x][y + 1] && !ret ){ //如果向上的那个点没有搜索到,就在墓室的范围内沿y轴向上走 , !ret是当前没有找到路径 point end; //记录搜索的下一个顶点的位置 end.x = x; end.y = y + 1; bool temp = true; //临时变量,用于记录是否与某一激光线段相交 for(int i = 0 ; i < num ; ++i ){ //遍历所有激光线段,判断是否相交 if( judge( start , end , seg[i].begin , seg[i].end ) ){ temp = false; break; //如果有一条相交的话,就记录并退出 } } if(temp){ //如果没有与任何激光线段相交的话,就向下一个点搜索 ret = findways( x , y + 1 , isthrough ); } } if( y - 1 >= 0 && isthrough[x][y - 1] && !ret ){ //如果向下的那个点没有搜索到,就在墓室的范围内沿y轴向下走 , !ret是当前没有找到路径 point end; end.x = x; end.y = y - 1; bool temp = true; for( int i = 0 ; i < num ; ++i ){ if( judge( start , end , seg[i].begin , seg[i].end ) ){ temp = false; break; } } if(temp){ //如果没有记录到相交的话 ret = findways( x , y - 1 , isthrough ); } } if(x + 1 <= m && isthrough[x + 1][y] && !ret ){ //如果向右的那个点没有搜索到,就在墓室的范围内沿x轴向右走 , !ret是当前没有找到路径 point end; end.x = x + 1; end.y = y; bool temp = true; for(int i = 0 ; i < num ; ++i ){ if(judge(start ,end ,seg[i].begin , seg[i].end)){ temp = false; break; } } if(temp){ //如果没有记录到相交的话 ret = findways( x + 1 , y , isthrough ); } } if(x - 1 >= 0 && isthrough[x - 1][y] && !ret ){ //如果向左的那个点没有搜索到,就在墓室的范围内沿x轴向左走, !ret是当前没有找到路径 point end; end.x = x - 1; end.y = y; bool temp = true; for(int i = 0 ; i < num ; ++i ){ if(judge(start ,end ,seg[i].begin , seg[i].end)){ temp = false; break; } } if(temp){ //如果没有记录到相交的话 ret = findways( x - 1 , y , isthrough ); } } } isthrough[x][y] = false; //标记当前点已经历 return ret; } int main(){ //读图 cin >> num; segment *seg = new segment[num]; //new一个num个激光线段结构的数组 for(int i = 0 ; i < n ; ++i ){ cin>>seg[i].begin.x>>seg[i].begin.y>>seg[i].end.x>>seg[i].end.y; //输入激光线段 } cin >> m >> n; //输入出口位置 vector<vector<bool> > isthrough(m + 1, vector<bool>(n + 1 , false)); //记录该点是否经历,避免产生回路;初始化为false ,因为包含0行0列,所以 + 1 bool ret = findways(0 , 0 , isthrough); if(ret){ cout<<"成功通过!"; } else{ cout<<"不能通过!"; } return 0; }

      

  • 相关阅读:
    九度 1172:哈夫曼树
    mac os 错误提示:下载失败 使用已购页面再试一次 解决方法
    WCF学习资料汇总
    豆瓣FM 歌词跟随插件
    大型网站架构和高并发的一些想法
    MAC OS 系统使用心得
    Windows 7 安装.net framework 4.0 失败,错误HRESULT 0xc8000222解决办法
    json官方学习档案
    转:查看sql语句执行时间/测试sql语句性能
    从数据库反向生成django的models
  • 原文地址:https://www.cnblogs.com/jhmu0613/p/6780821.html
Copyright © 2011-2022 走看看