hdu4885(最短路)

  好吧,很好的题目,题目的大意是:

  在一个平面上,有一个起点,一个终点,然后有好多加油站,每加一次油,可以走L公里,问最少要加多少次油?

  还是太水,一开始没想到最短路,实际就是看做n+2个节点,每个节点对于它距离小于L内的节点,可以建一个权值为1的边,然后运行一下最短路就好了。

  PS:巨大的坑点是,只要经过了加油站,就要加油,所以折腾了好久,不过也学习了一把处理斜率的方式。

  比如(0,0) 到(2,2), 中间有(1,1)是加油站, 所以到(1,1)必须加油。处理的方法就是在同一直线上的点,只跟第一次横坐标大于它的最近的点建边,如果还有横坐标之差或者纵坐标之差为0的需要小处理,也是最近的连边。 用map在进行斜率查找时优化到logn,另外最早要给节点按照横坐标排序。

#include "stdio.h"
#include "string.h"
#include "math.h"
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
using namespace std;

#define MAX 1003005
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define abs(a)  a < 0 ? a : (-a)
#define Mem(a,b) memset(a,b,sizeof(a))
int Mod = 1000000007;
double pi = acos(-1.0);
double eps = 1e-6;

typedef struct{
	int f,t,w,next;
}Edge;
Edge edge[MAX];
int head[1005];
int dist[1005];
bool visit[1005];
int kNum;

void addEdge(int f, int t, int w)
{
	edge[kNum].f = f;
	edge[kNum].t = t;
	edge[kNum].w = w;
	edge[kNum].next = head[f];
	head[f] = kNum ++;
}

__int64 gcd(__int64 x, __int64 y)
{
	return y == 0 ? x : gcd(y, x % y);
}

typedef struct{
	__int64 x,y;
}Node;
Node node[1005];
int T,n;
__int64 L;

typedef struct{
	int flag;
}KKK;
KKK kk[1005];

bool comp(KKK a, KKK b)
{
	if( node[a.flag].x == node[b.flag].x )
		return node[a.flag].y < node[b.flag].y;
	return node[a.flag].x < node[b.flag].x;
}

void work()
{
	for(int k = head[0]; k != -1; k = edge[k].next )
		dist[edge[k].t] = edge[k].w;
	visit[0] = true;

	for(int i = 0; i <= n; i ++){
		int t = -1, minV = 50000;
		for(int j = 1; j <= n + 1; j ++){
			if( !visit[j] && minV > dist[j]){
				minV = dist[j];
				t = j;
			}
		}
		if( t == -1 ) break;
//		if( dist[t] == 50000 ) break;
		if( t == n + 1 ) break;
		visit[t] = true;

		for(int k = head[t]; k != -1; k = edge[k].next){
			if( !visit[edge[k].t] && dist[edge[k].t] > dist[t] + edge[k].w){
				dist[edge[k].t] = dist[t] + edge[k].w;
			}
		}

	}

	if( dist[n+1] == 50000 ){
		printf("impossible\n");
	}
	else{
		printf("%d\n",dist[n+1] - 1);
	}
}


void solve()
{
	cin>>node[0].x>>node[0].y;
	cin>>node[n+1].x>>node[n+1].y;

	for(int i = 1; i <= n; i ++){
		cin>>node[i].x>>node[i].y;
	}

	for(int i = 0; i <= n + 1; i ++)
		kk[i].flag = i;

	sort(kk,kk+n+2,comp);

	Mem(head,-1);
	Mem(visit,false);
	fill(dist, dist + 1003, 50000);
	kNum = 0;

	map<__int64,int> ss;
	for(int i = 0; i <= n; i ++){
		int ii = kk[i].flag;
		ss.clear();
		bool flag1 = true;
		bool flag2 = true;
		for(int j = i + 1; j <= n + 1; j ++){
			int jj = kk[j].flag;
			if( ( node[ii].x - node[jj].x ) * ( node[ii].x - node[jj].x ) + ( node[ii].y - node[jj].y ) * ( node[ii].y - node[jj].y ) <= L * L ){
				//处理建边
				__int64 t = ( node[ii].x - node[jj].x ), z = ( node[ii].y - node[jj].y );
				if( t == 0 && flag1 ){
					addEdge(ii,jj,1);
					addEdge(jj,ii,1);
					flag1 = false;
					continue;
				}
				if( z == 0 && flag2 ){
					addEdge(ii,jj,1);
					addEdge(jj,ii,1);
					flag2 = false;
					continue;
				}
				if( t == 0 || z == 0 ) continue;


				//求斜率
				__int64 x = abs(t), y = abs(z);
				if( abs(t) < abs(z) ){
					x = z;
					y = t;
				}

				__int64 g = gcd(x,y);
				x /= g, y /= g;

				if( x < 0 ){
					x *= -1, y *= -1;
				}

				if( !ss.count(x*100001+y) ){
					addEdge(ii,jj,1);
					addEdge(jj,ii,1);
					ss[x*100001+y] = 1;
				}
			}
		}
	}

	work();

}



int main()
{
//	freopen("d:\\test.txt", "r", stdin);

	while( cin>>T ){
		while( T -- ){
			cin>>n>>L;
			solve();
		}
	}

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值