hrbust 1450 Farmer John【计算集合+最短路SPFA】

Farmer John
Time Limit: 5000 MSMemory Limit: 65536 K
Total Submit: 29(5 users)Total Accepted: 7(3 users)Rating: Special Judge: No
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
*/




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值