poj 1556 判断线段相交 + 最短路

题意:

从(0,5)到(10,5)中间有n堵墙,每个墙会开两个门。求从(0,5)到(10,5)的最短距离。n <= 18。

题解:

1.起点、终点、每个门的两个端点都看作一个点,先通过判断线段相交来求出点与点的初始距离(不用拐弯的距离)。这个题因为一条线段是垂直于x轴的,判断与另一条线段是否相交就简单了。

2.在第1步求出点与点的初始距离后直接套用dijkstra模板求最短路就ok了。

3.一直WA是因为特判n=0输出10,其实应该是10.00,脑子当时秀逗了。。。。。

#include<stdio.h>
#include<string.h> 
#include<algorithm>
#include<math.h>
using namespace std ;
#define eps 1e-8
struct Door
{
	double x , y[50] ;
} door[200] ; 
struct Node
{
	double x , y ;
} node[500] ;
int n , cnt ;
double dis[500] ;
double map1[500][500] ;
bool in(int a , int b , double x1 , double y1 , double x2 , double y2)
{
	double k1 = (y2 - y1) / (x2 - x1) ;
	double b1 = y1 - k1 * x1 ;
    double y = k1 * door[a].x + b1 ;
	if(y >= door[a].y[b * 2 - 1] && y <= door[a].y[b * 2] 
	|| fabs(y - door[a].y[b * 2 - 1]) < eps 
	|| fabs(y - door[a].y[b * 2]) < eps )
	   return 1 ;
	return 0 ;		
}
bool canlink(int a , int b , int c , int d)
{
	int i , j , k ;
	double x1 , y1 , x2 , y2 ;
	bool flag ;
	if(a == -1)
	{
		x1 = 0 ;
		y1 = 5 ;
	}
	else
	{
		x1 = door[a].x ;
		y1 = door[a].y[b] ;
	}
	if(c == n)
	{
		x2 = 10 ;
		y2 = 5 ;
	}
	else
	{
		x2 = door[c].x ;
		y2 = door[c].y[d] ;
	}
	for(i = a + 1 ; i < c ; i ++)
	{
		flag = 0 ;
		if(in(i , 1 , x1 , y1 , x2 , y2))
		   flag = 1 ;
		if(in(i , 2 , x1 , y1 , x2 , y2))
		   flag = 1 ;
		if(!flag)
		   return 0 ;
	}
	return 1 ;
}
void judge()
{
	int i , j , p , q ;
	int a , b ;
	double x1 , y1 , x2 , y2 ;
	for(i = -1 ; i <= n - 1 ; i ++)
	  for(j = i + 1 ; j <= n ; j ++)
		for(p = 1 ; p <= 4 ; p ++)
		  for(q = 1 ; q <= 4 ; q ++)
			 if(canlink(i , p , j , q))
			 {
			 	if(i == -1)
			 	{
			 	   a = 0 ;
				   x1 = 0 ; 
				   y1 = 5 ;	
				}
				else
				{
			 	   a = i * 4 + p ;
				   x1 = door[i].x ;
			 	   y1 = door[i].y[p] ;
				}
			 	if(j == n)
			 	{
			 	   b = cnt - 1 ;
				   x2 = 10 ;
				   y2 = 5 ;	
				}
				else
				{
				   b = j * 4 + q ;
			 	   x2 = door[j].x ;
			 	   y2 = door[j].y[q] ;	
				}
			 	map1[a][b] = map1[b][a] = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) ;
			 }
}
void dijkstra()
{
	int i , j , k ;
	bool vis[500] ;
	double min1 ;
	int temp ;
	memset(vis , 0 , sizeof(vis)) ;
	dis[0] = 0 ;
	for(i = 1 ; i < cnt ; i ++)
	    dis[i] = map1[0][i] ;    
	for(i = 0 ; i < cnt - 1 ; i ++)
	{
		min1 = 10000 ;
		temp = -1 ;
		for(j = 0 ; j < cnt ; j ++)
		    if(!vis[j] && dis[j] < min1 && fabs(dis[j] - min1) > eps)
		    {
		    	min1 = dis[j] ;
		    	temp = j ;
			}
		vis[temp] = 1 ;
		for(j = 0 ; j < cnt ; j ++)
		    dis[j] = min(dis[j] , dis[temp] + map1[temp][j]) ;
	}
}
int main()
{
   int i , j ;
   while(scanf("%d" , &n) && n != -1)
   {
   	 if(n == 0)
   	 {
   	   printf("10.00\n") ;
	   continue ;	
	 }
   	 cnt = 0 ;
   	 for(i = 0 ; i < n ; i ++)
   	 {
   	 	scanf("%lf" , &door[i].x) ;
   	 	for(j = 1 ; j <= 4 ; j ++)
   	 	   scanf("%lf" , &door[i].y[j]) ;
	 } 
	 cnt = 4 * n + 2 ;
	 for(i = 0 ; i < cnt ; i ++)
	     for(j = 0 ; j < cnt ; j ++)
		     map1[i][j] = 10000 ;
	 judge() ; //判断哪两个点可以相连。
	 dijkstra() ; //跑一遍最短路模板
	 printf("%.2f\n" , dis[cnt - 1]) ;     
   }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值