Farmer John | ||||||
| ||||||
Description | ||||||
Farmer John owns a lot of cows that graze in the fields and walk around happily. However, cow Bessie is very lazy and always takes the shortest route to the barn to get food. Farmer John wants to give Bessie some more walking exercises, so he placed some extra fences to make sure that Bessie cannot always take the shortest route and has to walk around the fences. Given the current location of Bessie, the location of the barn with the food, and all locations of the fences (modelled as line segments), farmer John wants you to compute the minimum distance that Bessie has to walk. Bessie is not allowed to cross any fence on her route, but she is allowed to touch the fences. | ||||||
Input | ||||||
The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format: • One line with four integers Bx, By, Fx and Fy satisfying −10, 000 ≤ Bx,By, Fx, Fy ≤ 10, 000: the location of Bessie and the location of the food. • One line with one integer N satisfying 0 ≤ N ≤ 100: the number of fences. • N lines, one for each fence, with four integers x1, y1, x2 and y2 satisfying −10, 000 ≤ x1, y1, x2, y2 ≤ 10, 000 and x1 != x2 or y1 != y2: the x- and y-coordinates of the begin and end points of this fence. Integers on the same line are separated by single spaces. The current location of Bessie and the location of the food will not lie on a fence, and fences will not touch or overlap. | ||||||
Output | ||||||
For every test case in the input, the output should contain a single real number, rounded and displayed to six digits after the decimal point, on a single line: the minimum walking distance. | ||||||
Sample Input | ||||||
3 0 0 10 0 1 -1 -100 -1 100 0 0 10 0 2 -1 -100 -1 100 5 4 5 -6 0 0 2 1 1 1 1 1 -1 | ||||||
Sample Output | ||||||
10.000000 12.806248 2.414214 | ||||||
Source | ||||||
Preliminaries BAPC 2010 |
题目大意:首先输入一个t,表示有t组数据,然后接下来一行,输入四个数,表示起点坐标和终点坐标,然后再输入一个数n,表示有n个栅栏,然后接下来n行,每行四个元素,表示一个栅栏的两个顶点,将一个栅栏看成一条线段,问从起点走到终点的最短距离。
思路:
1、对于每条线段的两个端点,我们将其看成节点,然后对于两个节点,如果能够相连的前提是:其两点之间没有栅栏相阻隔,所以我们需要对于每两个节点之间都判断一次有没有栅栏与之阻隔,其实也就是判断两条线段是否相交。
2、对于建成的图,跑一遍SPFA就可以啦!
Ac代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
#define INF 1000000000.0;
struct point
{
double x,y;
}a[50000];
double dis[5000000];
int vis[5000000];
int head[500000];
struct edge
{
int from,to,next;
double w;
}e[5000000];
int cont;
double multi(point p1,point p2,point p0)
{
return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
bool judge(point s1,point e1,point s2,point e2)//两个线段相交
{
return(max(s1.x,e1.x)>=min(s2.x,e2.x))&&
(max(s2.x,e2.x)>=min(s1.x,e1.x))&&
(max(s1.y,e1.y)>=min(s2.y,e2.y))&&
(max(s2.y,e2.y)>=min(s1.y,e1.y))&&
(multi(s1,s2,e1)*multi(s1,e1,e2)>=0)&&
(multi(s2,s1,e2)*multi(s2,e2,e1)>=0);
}
void add(int from,int to,double w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void SPFA(int ss,int n)
{
for(int i=0;i<=n;i++)dis[i]=INF;
memset(vis,0,sizeof(vis));
vis[ss]=1;dis[ss]=0;
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
s.pop();vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
double w=e[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(vis[v]==0)
{
s.push(v);
vis[v]=0;
}
}
}
}
printf("%.6f\n",dis[1]);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lf%lf%lf%lf",&a[0].x,&a[0].y,&a[1].x,&a[1].y);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&a[i*2].x,&a[i*2].y,&a[i*2+1].x,&a[i*2+1].y);
}
cont=0;
memset(head,-1,sizeof(head));
for(int i=0;i<=2*n+1;i++)
{
for(int j=0;j<=2*n+1;j++)
{
if(i==j)continue;
int flag=0;
for(int l=1;l<=n;l++)
{
if(i==l*2||i==l*2+1)continue;
if(j==l*2||j==l*2+1)continue;
if(judge(a[i],a[j],a[l*2],a[l*2+1])==1)
{
flag=1;break;
}
}
if(flag==1)continue;
double diss=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
add(i,j,diss);
}
}
SPFA(0,2*n+1);
}
}
/*
0 0 10 0
2
1 2 1 -2
5 5 5 -5
*/