ZOJ 3862 Intersection (dijkstra)

题意:有一个机器人和n个点,机器人从一个点只能走到与那个点距离小于等于r的另外一个点,而且机器人从一个角度转到另外一个角度的用时等于角度之差。求从第一个点走到第n个点的最短用时。

比较容易想到用dijkstra算法。需要用到一个二维的vis数组来记录访问情况,表示从一个点到另外一个点的访问情况(而不是一个点被访问一次之后就不能再被访问了)。细节就是注意浮点数的精度问题就行了。不算难题,但挺有意思的。

代码如下:

#include<iostream> 
#include<string> 
#include<queue> 
#include<algorithm> 
#include<cstdio> 
#include<vector> 
#include<queue> 
#include<climits> 
#include<cstring> 
#include<ctime>
#include<cmath>
#include<cstdlib>
using namespace std; 
const double pi=acos(-1.0);
const int maxn=25;
bool vis[maxn][maxn];
double initAng;
double ans;
int x[maxn],y[maxn];


struct node
{
	double angle,dist;
	int num,pre;
	node(int n,int p,double a,double d)
		:num(n),pre(p),angle(a),dist(d){}
	node(){}
	bool operator<(const node& b)const
	{
		return dist>b.dist;
	}
};

struct nxtPnt
{
	int nxt;
	double dist,angle;
	nxtPnt(int n,double a,double d)
		:nxt(n),angle(a),dist(d){}
	nxtPnt(){}
};

priority_queue< node >que;
vector< nxtPnt > vec[maxn];

void searchAns(int n)
{
	memset(vis,0,sizeof(vis));
	while(!que.empty()) que.pop();
	que.push(node(0,0,initAng,0.0));
	while(!que.empty())
	{
		node top=que.top();
		que.pop();
	//	cout<<"debug:"<<top.num<<' '<<top.dist<<' '<<top.pre<<' '<<vis[top.num][top.pre]<<endl;
		int cur=top.num;
		int pre=top.pre;
		if(vis[cur][pre]) continue;
		vis[cur][pre]=true;
		if(cur==n) 
		{
			ans=top.dist;
			//cout<<"haha:"<<ans<<endl;
			break;
		}

		int size=vec[cur].size();
		for(int i=0;i<size;i++)
		{
			int nxt=vec[cur][i].nxt;
			if(!vis[nxt][cur])
			{
				double angleToTurn=vec[cur][i].angle-top.angle;
				if(angleToTurn<0.0) angleToTurn=-1.0*angleToTurn;
				else if(angleToTurn>=360.0) angleToTurn-=360.0;
				if(angleToTurn>=180.0) angleToTurn=360.0-angleToTurn;//大于等于180度时转换成一个小于180的
				double distTo=vec[cur][i].dist+angleToTurn+top.dist;
				que.push(node(nxt,cur,vec[cur][i].angle,distTo));
			}
		}
	}

}

int main()
{
	int r,n;
	while(scanf("%d%d",&r,&n)!=EOF)
	{
		ans=INT_MAX+0.0;
		if(-1==r&&-1==n) break;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&x[i],&y[i]);
		}
		initAng=atan2((double)(y[n-1]-y[0]),(double)(x[n-1]-x[0]))/pi*180.0;
		for(int i=0;i<n;i++)  vec[i].clear();
		for(int i=0;i<n;i++)
		{
			for(int j=i+1;j<n;j++)
			{
				double distBet=sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(double)(y[i]-y[j])*(y[i]-y[j]));
				if(distBet<=r)
				{
					double angleBet1=atan2((double)(y[j]-y[i]),(double)(x[j]-x[i]));
					double angleBet2=atan2((double)(y[i]-y[j]),(double)(x[i]-x[j]));
					vec[i].push_back(nxtPnt(j,angleBet1/pi*180.0,distBet));	
					vec[j].push_back(nxtPnt(i,angleBet2/pi*180.0,distBet));
				}
			}
		}
		searchAns(n-1);
		if(ans==INT_MAX+0.0) printf("impossible\n");
		else
		{
			int fl=(int)floor(ans);
			if(ans-(double)fl>0.50) printf("%d\n",fl+1);
			else printf("%d\n",fl);
		}

	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值