hdu 4885 TIANKENG’s travel (最短路+判断三点共线)

TIANKENG’s travel

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 408    Accepted Submission(s): 100


Problem Description
TIANKENG has get a driving license and one day he is so lucky to find a car. Every day he drives the car around the city. After a month TIANKENG finds that he has got high driving skills and he wants to drive home. Assuming that we regard the map of Hangzhou as a two-dimensional Cartesian coordinate system, the coordinate of the school is (sx, sy), the coordinate of TIANKENG’s home is (ex,ey). There are n gas stations distributing along the road and the coordinate of the ith gas station is (xi, yi). Because there is something wrong with the car engine, TIANKENG can drive the car for L miles after every time he fills up the gas. Assuming that TIANKENG must fill up the gas when he passes by a gas station and the initial status of the tank is full. TIANKENG must drive on the straight line and he can only choose to drive to school or home or gas station. Your task is to tell TIANKENG the minimum times he needs to charge fuel to go home successfully.
 

Input
The first line contains a positive integer T(T<=30), referring to T test cases.
For each test case, the first line contains two integers n(0<=n<=1000), L(1<=L<=100000), which mean n gas stations in all and the distance TIANKENG can drive with the full tank respectively. The second line contains two integers sx, sy, which refers to the coordinate of the school.
The third line contains two integers ex, ey, which refers to the coordinate of TIANKENG’s home.
Then following n lines, each line contains two integer xi, yi, which refers to the coordinate of gas station.

Assuming that all the coordinates are different! All the coordinates satisfied [0,1000000].
 

Output
For each test case, if TIANKENG cannot go home successfully, print “impossible”(without quotes), otherwise print the minimum times of charging fuel.
 

Sample Input
  
  
2 2 1000 0 0 2000 1000 1000 0 2000 0 0 1000 0 0 2000 1000
 

Sample Output
  
  
2 impossible
 

Source
 

题意:
给你一个起点,一个终点和一些加油站,你只能走直线,只能到达这三种点,经过加油站必须加油,一次加油可以走L的距离,问最少经过加油站几次可以从起点到达终点。

思路:
一个点与直接能走到的点建边(不穿过其他点),然后求最短路就够了。要判断两点共线,采用的方法是枚举每个点为起始点(只与y大于它的带你建边),用map来维护这个点所在线的斜率(出发变为乘法),用一个数组记录这个斜率下的最小的y的id。

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <algorithm>
#define INF 0x3f3f3f3f
#define maxn 1005
#define MAXN 2000005
#define eps 1e-10
typedef long long ll;
using namespace std;

ll n,m,ans,cnt,sx;
bool vis[maxn];
ll dist[maxn],head[maxn],id[maxn][maxn];
struct node
{
    ll x,y,id;
    bool operator <(const node n1)const
    {
        if(x*n1.x>=0) return  y*n1.x<n1.y*x;
        return y*n1.x>n1.y*x;
    }
}q[maxn],cur;
struct Node
{
    ll v,w,next;
}edge[MAXN];

void addedge(ll u,ll v,ll w)
{
    cnt++;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
ll cal(ll i,ll j)
{
    ll xx=q[i].x-q[j].x,yy=q[i].y-q[j].y;
    return xx*xx+yy*yy;
}
void SPFA()
{
    ll i,j,nx,v;
    memset(vis,0,sizeof(vis));
    memset(dist,0x3f,sizeof(dist));
    sx=1;
    queue<ll>q;
    dist[sx]=0;
    vis[sx]=1;
    q.push(sx);
    while(!q.empty())
    {
        nx=q.front();
        vis[nx]=0;
        q.pop();
        for(i=head[nx];i;i=edge[i].next)
        {
            v=edge[i].v;
            if(dist[v]>dist[nx]+edge[i].w)
            {
                dist[v]=dist[nx]+edge[i].w;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
void solve()
{
    ll i,j,t;
    for(i=1;i<=n;i++)
    {
        map<node,ll>mp;
        ll tot=0;
        for(j=1;j<=n;j++)
        {
            if(q[j].y<q[i].y||q[j].y==q[i].y&&q[j].x<=q[i].x||cal(i,j)>m*m) continue ;
            cur.y=q[j].y-q[i].y;
            cur.x=q[j].x-q[i].x;
            t=mp[cur];
            if(t==0)
            {
                mp[cur]=++tot;
                id[i][tot]=j;
            }
            else
            {
                if(q[id[i][t]].y>q[j].y||q[id[i][t]].y==q[j].y&&q[id[i][t]].x>q[j].x)
                {
                    id[i][t]=j;
                }
            }
        }
        for(j=1;j<=tot;j++)
        {
            //printf("u:%I64d v:%I64d\n",i,id[i][j]);
            addedge(i,id[i][j],1);
            addedge(id[i][j],i,1);
        }
    }
}
int main()
{
    ll i,j,u,v,w,t;
    scanf("%I64d",&t);
    while(t--)
    {
        scanf("%I64d%I64d",&n,&m);
        n+=2;
        for(i=1;i<=n;i++)
        {
            scanf("%I64d%I64d",&q[i].x,&q[i].y);
            q[i].id=i;
        }
        cnt=0;
        memset(head,0,sizeof(head));
        solve();
        SPFA();
        if(dist[2]>=INF) printf("impossible\n");
        else printf("%I64d\n",dist[2]-1);
    }
    return 0;
}
/*
2
3 4
1 1
4 1
3 1
2 1
2 4

6 4
5 5
1 1
2 4
4 4
3 3
4 3
2 2
3 1
*/





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值