POJ The Doors(構成+最短パス)

  • ドア

  • 図1
    この質問は地図を作成するのが最も難しいと考えて、最短パスの地図作成が出てくるのを見つけます。たとえば、私の地図作成方法では、まず最初に、配列の始点と終点、および各セグメントの終点を壁として配置します。グラフの頂点(意味がないため、壁のルートの2つのポイントを削除します)。次に、seg [] []配列を使用して、各壁の各ラインセグメントの情報を表します。seg[i] []は、i番目の壁の情報を表します。この配列の目的は、主に次のとおりです。pos[]配列の2点ごとにトラバースするエッジを構築できるかどうかを判断します。これらの2つのポイントによって形成されるラインセグメントが、間の壁によってブロックされている場合(壁の特定のラインセグメントと交差している場合)、エッジを構築できません。そうでない場合、エッジが構築されます。
    ここでは、ラインセグメントabとcdが交差するかどうかを判断する方法について説明します。

    2つの線セグメントが交差する場合、ca⃗×cb⃗\ vec {ca} \ times \ vec {cb}があります。c a ××c b DA⃗×DB⃗\ VEC {DA} \回\ VEC {DB}d a ××d b 異なる符号とda⃗×ca⃗\ vec {da} \ times \ vec {ca}d a ××c a そしてdb⃗×cb⃗\ vec {db} \ times \ vec {cb}d b ××c b これも逆の符号です。この2つの条件が同時に満たされると交差点になります。1つの条件が満たされると書いただけですが、線分が交差するかどうかを判断するのに十分な条件ではありません。今知りました。
  • コード
#pragma GCC optimize(2)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring> 
 
using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<double,int> pa;
const double INF=0x3f3f3f3f;
const double eps=1e-8;
const int MAX_I=1000;//墙的数量 
const int MAX_N=MAX_I*7;//点的数量 
const int MAX_M=MAX_N<<1;//边的数量 
int head[MAX_N],e_cnt,N,cnt=0;; 
double d[MAX_N];
struct node{
    
    
	double x,y; 
}seg[MAX_I][6];//记录线段 
struct node_p{
    
    
	double x,y;
	int id;//对应一个顶点编号,便于后面建图 
	int bel;//属于哪一个墙 
}pos[MAX_N];//记录点的信息 
double dis_(node_p a,node_p b){
    
    
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
struct Edge{
    
    
	int to,next;
	double val;
}edge[MAX_M];
void add_edge(int u,int v,double dis){
    
    
	edge[e_cnt].to=v;
	edge[e_cnt].val=dis;
	edge[e_cnt].next=head[u];
	head[u]=e_cnt++;
	return ;
}
double fuck(node_p a,node c,node_p b){
    
    //计算叉乘 
	double x1,y1,x2,y2;
	x1=a.x-c.x;
	y1=a.y-c.y;
	x2=b.x-c.x;
	y2=b.y-c.y;
	return x1*y2-x2*y1;
}
bool is_inter(node_p a,node_p b,node c,node d){
    
    //叉乘判断线段a-b和c-d是否相交,如果相交,返回1 
	if(fuck(a,c,b)*fuck(a,d,b)<eps)//相乘结果小于0,说明是相交的 
	return 1;
	return 0;
}
//求最短路 
priority_queue<pa,vector<pa>,greater<pa> >Q;
void Dijkstra(int s){
    
    
	int i,j,k;
	for(i=0;i<cnt;i++)
	d[i]=INF;
	d[s]=0;
	while(!Q.empty())
	Q.pop();
	Q.push({
    
    0,s});
	while(!Q.empty()){
    
    
		pa jie=Q.top();
		Q.pop();
		int v=jie.sec;
		if(d[v]<jie.fir)
		continue;
		for(i=head[v];~i;i=edge[i].next){
    
    
			if(d[edge[i].to]>d[v]+edge[i].val){
    
    
				d[edge[i].to]=d[v]+edge[i].val;
				Q.push({
    
    d[edge[i].to],edge[i].to});
			}
		}
	}
	return ;
}
int main()
{
    
    
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	while(~scf("%d",&N)&&N!=-1){
    
    
		int i,j,k,g;
		double x,y;
		cnt=0;
		//将起点存入 
		pos[cnt].x=0;
		pos[cnt].y=5;
		pos[cnt].bel=0;
		pos[cnt].id=cnt++;
		for(i=1;i<=N;i++){
    
    
			scf("%lf",&x);
			seg[i][0].x=x;
			seg[i][0].y=0;
			for(j=1;j<=4;j++){
    
    
				scf("%lf",&y);
				seg[i][j].x=x;
				seg[i][j].y=y;
				pos[cnt].x=x;
				pos[cnt].y=y;
				pos[cnt].bel=i;
				pos[cnt].id=cnt++;
			}
			seg[i][5].x=x;
			seg[i][5].y=10;
		}
		//将终点存入 
		pos[cnt].x=10;
		pos[cnt].y=5;
		pos[cnt].bel=N+1;
		pos[cnt].id=cnt++;
		//建图
		memset(head,-1,sizeof(head));
		e_cnt=0;
		for(i=0;i<cnt-1;i++){
    
    
			for(j=i+1;j<cnt;j++){
    
    
				if(pos[i].bel==pos[j].bel)//在同一个墙上的两个点
				continue;
				double dis=dis_(pos[i],pos[j]);
				if(pos[j].bel-pos[i].bel==1){
    
    //说明是相邻的墙,可以直接连成一条边 
					add_edge(pos[i].id,pos[j].id,dis);
					add_edge(pos[j].id,pos[i].id,dis);
					continue;
				}
				//判断这两个点有没有被线段隔开 
				bool flag=0;
				for(k=pos[i].bel+1;k<pos[j].bel;k++)//看看中间的墙能不能挡住他们
					for(g=0;g<=4;g+=2){
    
    // 每个墙的三条线段
						if(is_inter(pos[i],pos[j],seg[k][g],seg[k][g+1])){
    
    
							flag=1;
							break;
						}
					}
					if(flag)
					break;
				}
				if(!flag){
    
    
					add_edge(pos[i].id,pos[j].id,dis);
					add_edge(pos[j].id,pos[i].id,dis);				
				}
			}
		}
		//求最短路
		Dijkstra(0);
		prf("%.2f\n",d[cnt-1]);
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_43311695/article/details/108843442