Uva393 The Doors.

原题链接:点击打开链接

题目大意:在一个(10*10)平面内,求出发点(0,5)到终点(10,5) 的最短距离。


计算几何的基本题目,利用叉积来判断线段门与门之间是否能够相连,然后用dijkstra求最短路经

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;

const double maxdist=0x7FFFFFFF;
int wall_num;
int edge_num;
int point_num;
double precision=0.00000001;//用来控制判断精度
double dist[100];
double point_dist[100][100];
struct edge_node{
  double x1,x2,y1,y2;
}edge[80];
struct point_node{
  double x,y;
}point[100];

/*
 *在边的集合里添加边
 *在点的集合里添加点
 */
void add_edge(double x1,double y1,double x2,double y2){
  edge[edge_num].x1=x1;
  edge[edge_num].x2=x2;
  edge[edge_num].y1=y1;
  edge[edge_num].y2=y2;
  ++edge_num;
}
void add_point(double x,double y){
  point[point_num].x=x;
  point[point_num].y=y;
  point_num++;
}

/*
 *使用dijkstra求两点之间
 */
void dijkstra(){
  for (int i=1;i<point_num;i++)
    dist[i]=maxdist;
  bool reach[100];
  memset(reach,true,sizeof(reach));
  for (int i=1;i<=point_num;i++){
    int pos;
    double value=maxdist;
    for (int j=0;j<point_num;j++)
      if (dist[j]<value && reach[j]){
	value=dist[j];
	pos=j;
      }
    reach[pos]=false;
    for (int j=0;j<point_num;j++)
      if (reach[j] && 
	  dist[pos]+point_dist[pos][j]<dist[j]){
	dist[j]=dist[pos]+point_dist[pos][j];
      }
  }
}

/*
 *以下一连串子程序用叉积来判断两条线段是否相交
 */
double det(double x1,double y1,double x2,double y2){
  return x1*y2-x2*y1;
}
double cross(point_node a,point_node b,point_node c){
  return det(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);
}
int cmp(double d){
  if (fabs(d)<precision)
    return 0;
  return (d>0)?1:-1;
}
bool segment_cross_simple(point_node a,point_node b,point_node c,point_node d){
  if (((cmp(cross(a,c,d))^cmp(cross(b,c,d)))==-2)&&
      ((cmp(cross(c,a,b))^cmp(cross(d,a,b)))==-2))
    return true;
  else
    return false;
}
/*
 *解决过程
 */
void solve(){
  /*
   *初始化过程
   */
  memset(edge,0,sizeof(edge));
  memset(point,0,sizeof(point));
  memset(dist,0,sizeof(dist));
  memset(point_dist,0,sizeof(point_dist));
  //点集和边集清零
  edge_num=0;
  point_num=0;
  add_point(0,5);
  add_point(10,5);
  //增加起点和终点
  for (int i=1;i<=wall_num;i++){
    double x,y1,y2,y3,y4;
    cin >> x >> y1 >> y2 >> y3 >> y4;
    
    //输入每个墙,并添加墙所对应的边
    add_edge(x,0,x,y1);
    add_edge(x,y2,x,y3);
    add_edge(x,y4,x,10);
    //添加墙所对应的新增顶点
    add_point(x,y1);
    add_point(x,y2);
    add_point(x,y3);
    add_point(x,y4);
  }
  
  for (int i=0;i<point_num;i++)
    for (int j=0;j<point_num;j++)//枚举任意两个点
      if (i!=j){//如果他们不是同一个点
	bool link=true;
	for (int k=0;k<edge_num;k++){
	  point_node lv,lv2;
	  lv.x=edge[k].x1;lv.y=edge[k].y1;
	  lv2.x=edge[k].x2;lv2.y=edge[k].y2;
	  if (segment_cross_simple(point[i],point[j],lv,lv2))
	    link=false;
	}
	if (link)
	  point_dist[i][j]=sqrt(pow(point[i].x-point[j].x,2)+
				pow(point[i].y-point[j].y,2));
	else
	  point_dist[i][j]=maxdist;
      }
  //对于任意两个顶点求他们之间的路径

  dijkstra();
  //求出源点开始的dijkstra

  cout << setiosflags(ios::fixed) 
       << setprecision(2) 
       << dist[1] << endl; 
}

/*
 *主过程
 */
int main(){
  cin >> wall_num;
  while (wall_num!=-1){
    solve();
    cin >> wall_num;
  }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章