有趣的问题
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length.
-
输入
-
The input data for the illustrated chamber would appear as follows.
2
4 2 7 8 9
7 3 4.5 6 7
The first line contains the number of interior walls. Then there is a line for each such wall, containing five real numbers. The first number is the x coordinate of the wall (0 < x < 10), and the remaining four are the y coordinates of the ends of the doorways in that wall. The x coordinates of the walls are in increasing order, and within each line the y coordinates are in increasing order. The input file will contain at least one such set of data. The end of the data comes when the number of walls is -1.
输出
- The output should contain one line of output for each chamber. The line should contain the minimal path length rounded to two decimal places past the decimal point, and always showing the two decimal places past the decimal point. The line should contain no blanks. 样例输入
-
1 5 4 6 7 8 2 4 2 7 8 9 7 3 4.5 6 7 -1
样例输出
-
10.00 10.06
来源
- 黑书 上传者
题意:
你需要找到从(0,5)到(10,5)的最短路径,在这着之中有墙阻隔,可以从墙的门过去(如图)。
输入第一行为墙的个数
第二行为五个实数,第一个为墙的横坐标,后面为墙中门两边的纵坐标。
思路:
拿到这个题,首先要知道这个题是一个全局最优问题,所以每一步求得最短的距离去相加得出结果一定wa。
所以要用到类似图里的最短路径算法(迪杰斯特拉算法)
所以现在的重点是要想把题目这种图转化为图,并在各点之间建立联系。这里需要用一个容器存所有点,另一个存所有边。具体见代码注释。
需要注意的一点是,一个点判断与其他点是否会被阻挡的时候,不仅要判断相邻列还要判断间隔列(求直线方程判断与线段是否相交)。
#include<bits/stdc++.h> using namespace std; struct node { double x, y; int k; }; struct node1{ double y1, y2; };//用来存所有阻碍墙 struct node2{ double a, b, c, d, z ,e; }te[1005]; bool cmp(node2 a, node2 b) { return a.a < b.a; } vector<node> Ve[105];//申明node类型的邻接表 vector<node1> Vey[105]; double map1[105][105];//图 int kk; double dis()//迪杰斯特拉算法思想 { double dis[105], minv = 99999.0; int vis[105], i, j, k; for(i = 1 ; i <= kk ; i++) { dis[i] = map1[1][i]; vis[i] = 0; } // printf("-->%0.2lf\n", dis[kk]); vis[1] = 1; for(i = 1 ; i < kk ; i++) { minv = 99999.0; for(j = 1 ; j <= kk ; j++) { if(vis[j] == 0 && dis[j] < minv) { k = j; minv = dis[j]; } } vis[k] = 1; for(j = 1 ; j <= kk ; j++) { if(vis[j] == 0 && dis[j] > dis[k]+map1[k][j]) { // printf("aaa\n"); dis[j] = dis[k]+map1[k][j]; } } } return dis[kk]; } int main() { int n, i, j; //double num[20]; while(~scanf("%d", &n)) { if(n == -1) break; //memset(map, 0x3f3f3f3f, sizeof(map)); for(i = 0 ; i < 105 ; i++) { Ve[i].clear(); Vey[i].clear(); } for(i = 0 ; i < 105 ; i++){ for(j = 0 ; j < 105 ; j++){ map1[i][j] = 99999.0; } }//全部初始化为最大值 for(i = 0 ; i < 105 ; i++){ map1[i][i] = 0; }//自己到自己距离为0 // double a, b, c, d, e; int qk = 1, k1, zk, zi,z; kk=1; node ns; ns.x = 0; ns.y = 5;//起点 ns.k = kk; kk++; Ve[1].push_back(ns); //num[qk] = 0; qk=2; for(i = 0 ; i < n ; i++){ scanf("%lf %lf %lf %lf %lf", &te[i].a, &te[i].b, &te[i].c, &te[i].d, &te[i].e); } sort(te, te+n, cmp); //按x坐标排序 for(i = 0 ; i < n; i++)//构图 { node na, nb, nc, nd; // scanf("%lf %lf %lf %lf %lf", &a, &b, &c, &d, &e); //num[qk] = a; na.x = te[i].a; na.y = te[i].b; na.k = kk; kk++; Ve[qk].push_back(na); nb.x = te[i].a; nb.y = te[i].c; nb.k = kk; kk++; Ve[qk].push_back(nb); nc.x = te[i].a; nc.y = te[i].d; nc.k = kk; kk++; Ve[qk].push_back(nc); nd.x = te[i].a; nd.y = te[i].e; nd.k = kk; kk++; Ve[qk].push_back(nd); node1 ya, yb, yc;//存一堵墙中不能过的部分 ya.y1 = 0; ya.y2 = te[i].b; Vey[qk].push_back(ya); yb.y1 = te[i].c; yb.y2 = te[i].d; Vey[qk].push_back(yb); yc.y1 = te[i].e; yc.y2 = 10; Vey[qk].push_back(yc); // printf("%d\n", qk); qk++; } node la; la.x = 10; la.y = 5; la.k = kk; Ve[qk].push_back(la);//printf("-->%d\n", qk); qk++;//总墙数 for(i = 1 ; i < qk-1 ; i++) { //printf("%d %d cc\n", i, Ve[i].size()); for(j = 0 ; j < Ve[i].size() ; j++) { //printf("%d dd\n", i); for(k1 = 0 ; k1 < Ve[i+1].size() ; k1++)//判断相邻列 { double xx = (Ve[i][j].x-Ve[i+1][k1].x)*(Ve[i][j].x-Ve[i+1][k1].x); double yy = (Ve[i][j].y-Ve[i+1][k1].y)*(Ve[i][j].y-Ve[i+1][k1].y); double s = sqrt(xx+yy); int be = Ve[i][j].k; int en = Ve[i+1][k1].k; // printf("-->%d %d %d %d %d\n",i+1,Ve[i+1].size(), k1, be, en); map1[be][en] = map1[en][be] = s; } // printf("%d bb\n", i); for(k1 = i+2 ; k1 < qk ; k1++)//从当前点间隔一列开始判断 { //printf("aa\n"); for(zk = 0 ; zk < Ve[k1].size() ; zk++) { int flag = 0; for(z = k1-1; z > i ; z--) { //double sy = (Ve[z][0].x-Ve[i][j].x)*1.0/(Ve[i][j].x-Ve[k1][zk].x)*(Ve[k1][zk].y-Ve[i][j].y)+Ve[i][j].y; // printf("---->%0.2lf\n", sy); double k = (Ve[i][j].y - Ve[k1][zk].y)/(Ve[i][j].x-Ve[k1][zk].x); double b = Ve[i][j].y - k*Ve[i][j].x; double sy = k*Ve[z][0].x+b;//先求出直线方程 判断y值位置来判断是否穿过墙 for(zi = 0 ; zi < Vey[z].size() ; zi++) { if(sy > Vey[z][zi].y1 && sy < Vey[z][zi].y2) //过不去 { flag = 1; break; } } if(flag == 1) break; } if(flag == 0) { double xx = (Ve[i][j].x-Ve[k1][zk].x)*(Ve[i][j].x-Ve[k1][zk].x); double yy = (Ve[i][j].y-Ve[k1][zk].y)*(Ve[i][j].y-Ve[k1][zk].y); double s = sqrt(xx+yy); int be = Ve[i][j].k; int en = Ve[k1][zk].k; map1[be][en] = map1[en][be] = s; } } } } } /*for(i = 1 ; i <= kk ; i++){ for(j = 1 ; j <= kk ; j++){ printf("%0.2lf ", map[i][j]); } printf("\n"); } printf("aaa\n");*/ //printf("bb\n"); double ans = dis(); printf("%0.2lf\n", ans); } return 0; }
-
The input data for the illustrated chamber would appear as follows.