POJ The Doors (Composition + Shortest Path)

  • The Doors
  • Thinking
    figure 1
    this question is the most difficult to build a map, find a shortest path map building will come out after, say under my map building method, first of all I pos [] array will start and end point and the endpoint of each segment as a wall The vertices of the graph (remove the two points of the wall root, because it is meaningless). Then use the seg[][] array to represent the information of each line segment of each wall, seg[i][] represents the information of the i-th wall, the purpose of this array is mainly to: traverse every two points of the pos[] array Judge whether the edge can be built. If the line segment formed by these two points is blocked by the wall between (intersects with a certain line segment in the wall), the edge cannot be built, otherwise the edge is built.
    Here I will talk about how to judge whether the line segments ab and cd intersect?

    If two line segments intersect, there is ca ⃗ × cb ⃗ \vec{ca}\times\vec{cb}c a ×cb da ⃗ × db ⃗ \ vec {da} \ times \ vec {db}d a ×db Different sign and da ⃗ × ca ⃗ \vec{da}\times\vec{ca}d a ×c a And db ⃗ × cb ⃗ \vec{db}\times\vec{cb}db ×cb It is also an opposite sign. If these two conditions are met at the same time, it is the intersection. I only wrote that one condition is satisfied, but this is not a sufficient condition for judging the intersection of line segments. This is because the meaning of this question is given by the special data, I hope everyone Just know.
  • Code
#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;
}

Guess you like

Origin blog.csdn.net/weixin_43311695/article/details/108843442