HDU_1245_Saving James Bond_最短路

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1245

题意:给一个已知直径的圆形岛,然后岛的附近是湖,湖里有一些点,以坐标的形式给出,最外层是矩形的终点。

给定跳跃的距离d,让你判断是否能跳到最外层,如果能就输出最短距离以及这个最短跳的步数。


题解:

  这题重点在建图,在松弛操作那里也要修改一下。详细看代码。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
#include<functional>
#define cl(a,b) memset(a,b,sizeof(a));
#define FFC(i,a,b) for(int i=a;i<=b;i++)
#define FFI(i,a,b) for(int i=a;i>=b;i--)
#define pb push_back
#define LL long long
using namespace std;
void fre(){freopen("c:\\acm\\input.txt","r",stdin);}
const double INF=1e9,eps=1e-5;
const int MAXN=110,MAXM=11000;
typedef pair<double,int>P;
priority_queue<P,vector<P>,greater<P> >Q;
int v[MAXM],g[MAXN],nxt[MAXM],ed,i,x,N,pre[MAXN];
double w[MAXM],d[MAXN];
int n,xx,yy,cnt,K;
void init(int n){for(i=1,ed=0,N=n;i<=n;i++)g[i]=0;}
void adg(int x,int y,double z){v[++ed]=y,w[ed]=z,nxt[ed]=g[x],g[x]=ed;}
void dijkstra(int S){
	for(i=1;i<=N;i++)d[i]=INF,pre[i]=S;Q.push(P(d[S]=0,S));
	while(!Q.empty()){
		P t=Q.top();Q.pop();
		if(t.first>d[x=t.second])continue;
		for(i=g[x];i;i=nxt[i])if(d[x]+w[i]<d[v[i]]&&!(w[i]>K)){//距离必须小于K才能跳
			pre[v[i]]=x;//记录路径
			Q.push(P(d[v[i]]=d[x]+w[i],v[i]));
		}
	}
}
struct dt{
	int x,y;
}a[110];
int abs(int a){return a<eps?-a:a;}
double getdis(int a,int b,int c,int d){return sqrt(1.0*(a-c)*(a-c)+(b-d)*(b-d));}
void build_g(){
	//以1为起点
	FFC(i,2,cnt){
		double tmp=getdis(0,0,a[i].x,a[i].y);
		if(tmp<=7.5){adg(1,i,0);adg(i,1,0);}
		else if(tmp-7.5-K<=eps&&tmp-7.5>eps){adg(1,i,tmp-7.5);adg(i,1,tmp-7.5);}
	}
	FFC(i,2,cnt)FFC(j,i,cnt){
		if(i==j){adg(i,j,0);adg(j,i,0);}
		else{
			double tmp=getdis(a[i].x,a[i].y,a[j].x,a[j].y);
			adg(i,j,tmp);
			adg(j,i,tmp);
		}
	}
	//cnt+1为终点
	FFC(i,2,cnt){
		int min=(50-abs(a[i].x))>(50-abs(a[i].y))?(50-abs(a[i].y)):(50-abs(a[i].x));
		adg(cnt+1,i,(double)min);
		adg(i,cnt+1,(double)min);
	}
}
int getlong(){
	int an=0,i=cnt+1;
	while(pre[i]!=i){
		i=pre[i],an++;
	}
	return an;
}
int main(){
	//fre();
	while(~scanf("%d%d",&n,&K)){
		cnt=1;
		FFC(i,1,n){
			scanf("%d%d",&xx,&yy);
			if(xx<50&&yy<50)a[++cnt].x=xx,a[cnt].y=yy;
		}
		//特判,如果K大于42.5可一步跳到岸边
		if(K>=42.5){printf("42.50 1\n");continue;}
		init(cnt+1);
		build_g();//建图
		dijkstra(1);
		double ans=d[cnt+1];
		if(ans<INF)printf("%.2lf %d\n",ans,getlong());
		else printf("can't be saved\n");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值