2017阿里实习生招聘编程题之墓室
2017-04-27 14:36
399 查看
题目描述: 一个摸金校尉要通过一个矩形墓室,入口的位置为(0,0),出口位置为(m,n)。墓室中散步着一些散光发射器,某些激光发射器之间有激光。m,n和激光的起始和终止位置(x1,y1,x2,y2)均为整数。请问他能否不碰到激光,成功通过墓室。
题目分析: 首先通过深度优先遍历(DFS)根据直线是否相交确定所有的激光线段所构成的连通分量,例如,右图有3个连通分量,分别记录每个连通分量的横坐标的最小值和最大值,纵坐标的最小值和最大值。 那么当有连通分量横坐标最小最大值分别为0和m, 或纵坐标最小最大值为0和n, 或横、纵坐标最小值都为m ,或横、纵坐标的最大值分别为m和n时,不能通过墓室,这样求很容易写出程序了。
输入:
由于时间仓促,代码可能有些bug或考虑不全的地方,欢迎各位大佬给出建议。
题目分析: 首先通过深度优先遍历(DFS)根据直线是否相交确定所有的激光线段所构成的连通分量,例如,右图有3个连通分量,分别记录每个连通分量的横坐标的最小值和最大值,纵坐标的最小值和最大值。 那么当有连通分量横坐标最小最大值分别为0和m, 或纵坐标最小最大值为0和n, 或横、纵坐标最小值都为m ,或横、纵坐标的最大值分别为m和n时,不能通过墓室,这样求很容易写出程序了。
#include<iostream> #include<algorithm> #include<vector> int cnt = 1; //cnt定义图的连通分量的个数, 第一个连通分量(cnt=1),第2个(cnt=2),依次类推 struct Point //point为定义的坐标(x,y) { int x; int y; }; struct lt //存放每个连通分量的 横,纵坐标的最小最大值 { int x_min; //横坐标最小值 int x_max; int y_min; int y_max; }; struct lt liantong[100]; //存放每个连通分量的4个最大最小坐标值 int visited[100] = { 0 }; //标记该条线是否被访问, 线之间是否相连的连通分量的个数 using namespace std; double mult(Point a, Point b, Point c) //相当于求斜率 K(bc)-K(ba) { return (a.x - c.x)*(b.y - c.y) 4000 - (b.x - c.x)*(a.y - c.y); } //aa, bb为一条线段两端点 cc, dd为另一条线段的两端点 相交返回true, 不相交返回false bool intersect(Point aa, Point bb, Point cc, Point dd) //判断2条直线是否相交 { if (max(aa.x, bb.x)<min(cc.x, dd.x)) { return false; } if (max(aa.y, bb.y)<min(cc.y, dd.y)) { return false; } if (max(cc.x, dd.x)<min(aa.x, bb.x)) { return false; } if (max(cc.y, dd.y)<min(aa.y, bb.y)) { return false; } if (mult(cc, bb, aa)*mult(bb, dd, aa)<0) { return false; } if (mult(aa, dd, cc)*mult(dd, bb, cc)<0) { return false; } return true; } void DFS(vector<Point>& vec1, vector<Point>& vec2, int k, int visited[100]) //深度优先确定连通分量的个数 { visited[k] = cnt; for (int i = 0; i<vec1.size(); i++) { if (visited[i] == 0) //如果还没有被访问过 { if (intersect(vec1[k], vec2[k], vec1[i], vec2[i])) //如果k和i 这2条直线连通 DFS(vec1, vec2, i,visited); } } } int main() { int i, j, m, n, k; cin >> m >> n; cout << "请输入激光的条数:" << endl; cin >> k; cout << "请输入k个激光的坐标,每条线有4个点,分别为坐标(x1,y1),(x2,y2):" << endl; vector<Point> vec1, vec2; for (i = 0; i<k; i++) { Point point1, point2; cin >> point1.x >> point1.y >> point2.x >> point2.y; vec1.push_back(point1); vec2.push_back(point2); } // int *visited = new int[k]; //标记该条线是否被访问, 线之间是否相连的连通分量的个数 // memset(visited, 0, sizeof(visited)); for (i = 0; i<k; i++) { if (visited[i] == 0) { DFS(vec1, vec2, i, visited); liantong[cnt].x_min = min(vec1[i].x, vec2[i].x); liantong[cnt].x_max = max(vec1[i].x, vec2[i].x); liantong[cnt].y_min = min(vec1[i].y, vec2[i].y); liantong[cnt].y_min = max(vec1[i].y, vec2[i].y); for (j = 0; j<k; j++) { if (visited[j] == cnt) //如果该线段属于第cnt个连通分量 { if (min(vec1[j].x, vec2[j].x)<liantong[cnt].x_min) liantong[cnt].x_min = min(vec1[j].x, vec2[j].x); if (max(vec1[j].x, vec2[j].x)>liantong[cnt].x_max) liantong[cnt].x_max = max(vec1[j].x, vec2[j].x); if (min(vec1[j].y, vec2[j].y)<liantong[cnt].y_min) liantong[cnt].y_min = min(vec1[j].y, vec2[j].y); if (max(vec1[j].y, vec2[j].y)>liantong[cnt].y_max) liantong[cnt].y_max = max(vec1[j].y, vec2[j].y); } } cnt++; } } bool flag = false; for (i = 1; i <= cnt; i++) //一共cnt个连通分量 { //直线连通分量把密室完全挡住了 if ((liantong[i].x_min == 0 && liantong[i].x_max == m) || (liantong[i].y_min == 0 && liantong[i].y_max == n)|| (liantong[i].x_min == 0 && liantong[i].y_min == 0) || (liantong[i].x_max == m && liantong[i].y_max == n)) { cout << "不能成功通过密室" << endl; flag = true; break; } } if (!flag) cout << "可以通过密室" << endl; system("pause"); return 0; }
输入:
由于时间仓促,代码可能有些bug或考虑不全的地方,欢迎各位大佬给出建议。
相关文章推荐
- 2017阿里实习生招聘考试编程题
- 2017阿里实习生招聘编程题之相亲约会
- 2017京东实习生招聘编程题——站队抓小偷(python)
- 2017阿里巴巴实习生招聘编程题
- 腾讯2017暑假实习生招聘笔试编程题(2)
- 2017阿里实习生在线编程题
- 2017网易雷火实习生招聘编程题
- 2017百度实习生招聘编程题
- 2017百度实习生招聘编程题
- 今日头条2017暑期实习生招聘笔试编程题之函数最宽尖峰
- 京东2017实习生招聘在线笔试编程题
- 2017阿里研发工程师C/C++实习生招聘笔试题
- 奇虎360 2017暑期实习生招聘笔试编程题之跑步和剪气球
- 京东2017实习生招聘在线笔试编程题题解
- 阿里2015实习生招聘在线测试----编程题,设计有限任务响应队列
- 京东2017实习生招聘在线笔试编程题
- 2017网易实习生招聘编程题之魔力手环(矩阵幂)
- 网易2017暑期实习生招聘笔试编程题之小易背单词
- 2017腾讯实习生招聘笔试编程题
- 京东2017实习生招聘——在线笔试编程题总结