POJ The Doors (Zusammensetzung + kürzester Weg)

  • Die Türen
  • Wenn Sie
    Abbildung 1
    der Meinung sind, dass diese Frage am schwierigsten ist, eine Karte zu erstellen, finden Sie einen Kartenaufbau mit dem kürzesten Pfad, nachdem beispielsweise unter meiner Kartenerstellungsmethode zunächst das Start- und Endpunkt von pos [] und der Endpunkt jedes Segments als Wand angezeigt werden Die Eckpunkte des Diagramms (entfernen Sie die beiden Punkte der Wandwurzel, da dies bedeutungslos ist). Verwenden Sie dann das Array seg [] [], um die Informationen jedes Liniensegments jeder Wand darzustellen. Seg [i] [] repräsentiert die Informationen der i-ten Wand. Der Zweck dieses Arrays besteht hauptsächlich darin, alle zwei Punkte des Arrays pos [] zu durchlaufen Beurteilen Sie, ob die Kante gebaut werden kann. Wenn das durch diese beiden Punkte gebildete Liniensegment durch die Wand zwischen (die ein bestimmtes Liniensegment in der Wand schneidet) blockiert wird, kann die Kante nicht gebaut werden, andernfalls wird die Kante gebaut.
    Hier werde ich darüber sprechen, wie zu beurteilen ist, ob sich die Liniensegmente ab und cd schneiden.

    Wenn sich zwei Liniensegmente schneiden, gibt es ca ⃗ × cb ⃗ \ vec {ca} \ times \ vec {cb}c a ×c b da ⃗ × db ⃗ \ vec {da} \ times \ vec {db}d a ×d b Unterschiedliches Vorzeichen und da ⃗ × ca ⃗ \ vec {da} \ times \ vec {ca}d a ×c a Und db ⃗ × cb ⃗ \ vec {db} \ times \ vec {cb}d b ×c b Es ist auch ein entgegengesetztes Vorzeichen. Wenn diese beiden Bedingungen gleichzeitig erfüllt sind, ist es der Schnittpunkt. Ich habe nur geschrieben, dass eine Bedingung erfüllt ist, aber dies ist keine ausreichende Bedingung für die Beurteilung des Schnittpunkts der Liniensegmente. Dies liegt daran, dass die in dieser Frage angegebenen Daten etwas Besonderes sind. Ich hoffe, dass alle Weiß es einfach.
  • 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;
}

Ich denke du magst

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