題意:找從起點到終點的最短路徑。
題解:可以知道,但凡兩點不能直達,則一定是沿著牆邊界點走的,這樣才能保證路徑最短。那麼只需要再所有可以直達的點間連上一條邊,求一次最短路徑。注意判斷兩線段是否相交應該是判斷“嚴格相交”,即不包含端點。
#include <cmath>#include <cstdio>/*#include <iostream> //不知道為什麼加上這兩句就報一些奇怪的錯誤····using namespace std; */#define MAX 500#define eps 1e-8#define INF 999999999999#define zero(x) ( ((x) > 0 ? (x) : -(x)) < eps )struct Point { double x, y;};struct Line { Point a, b;};Point point[MAX];Line line[MAX];double dis[MAX], edge[MAX][MAX];bool vis[MAX];double xmult ( Point p1, Point p2, Point p0 ) // 叉積{return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);}bool oPointosite_side ( Point p1, Point p2, Point l1, Point l2 ) // 判斷同側或者異側{return xmult(l1,p1,l2) * xmult(l1,p2,l2) < -eps;}bool intersect_ex ( Point u1, Point u2, Point v1, Point v2 ) // 判斷是否相交{return oPointosite_side(u1,u2,v1,v2) && oPointosite_side(v1,v2,u1,u2);}double distance ( Point p1, Point p2 ) // 求兩點間的距離{return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));}bool check ( int lnum, Point p1, Point p2 ) // 對於任意兩個點i,j,枚舉所有的邊,若它不與任意邊相交,則返回true{for ( int i = 1; i <= lnum; i++ ){if ( intersect_ex ( p1, p2, line[i].a, line[i].b ) )return false;}return true;}void build_map ( int pnum, int lnum ){int i, j;for ( i = 0; i < pnum; i++ )for ( j = i + 1; j <= pnum; j++ )edge[i][j] = edge[j][i] = INF;for ( i = 0; i < pnum; i++ ){for ( j = i + 1; j <= pnum; j++ )if ( check ( lnum, point[i], point[j] ) ) // 若 i, j 之間沒有牆壁阻擋,則可連一條邊edge[i][j] = edge[j][i] = distance ( point[i], point[j] );}}double Dijkstra ( int pnum ){int i, j, k;for ( i = 0; i <= pnum; i++ ){dis[i] = edge[0][i];vis[i] = 0;}vis[0] = true;dis[0] = 0;for ( i = 1; i <= pnum; i++ ){double minc = INF;for ( j = 0; j <= pnum; j++ ){if ( ! vis[j] && minc > dis[j] ){minc = dis[j];k = j;}}if ( minc == INF ) break;vis[k] = true;dis[k] = minc;for ( j = 0; j <= pnum; j++ ){if ( ! vis[j] && dis[j] > dis[k] + edge[k][j] )dis[j] = dis[k] + edge[k][j];}}return dis[pnum];}int main(){int n;while ( scanf("%d",&n) ){if ( n == -1 ) break;double x, y1, y2, y3, y4;int i, p = 0, l = 0;point[0].x = 0; point[0].y = 5; // 0 為起點for ( i = 1; i <= n; i++ ){scanf("%lf %lf %lf %lf %lf", &x, &y1, &y2, &y3, &y4 );l++;line[l].a.x = line[l].b.x = x;line[l].a.y = 0; line[l].b.y = y1;l++;line[l].a.x = line[l].b.x = x;line[l].a.y = y2; line[l].b.y = y3;l++;line[l].a.x = line[l].b.x = x;line[l].a.y = y4; line[l].b.y = 10;p++;point[p].x = x; point[p].y = y1;p++;point[p].x = x; point[p].y = y2;p++;point[p].x = x; point[p].y = y3;p++;point[p].x = x; point[p].y = y4;}p++;point[p].x = 10; point[p].y = 5; // p 為終點build_map ( p, l );double res = Dijkstra ( p );printf("%.2lf\n",res);}return 0;}