题目大意:
给你一幅图,上面有一些“街道”和“标记边”组成。问你某两点之间的最短路径。(“标记边”用来规定“街道”的方向)。
街道:表示两点之间有边相连。
标记边:标记边的一端悬空,令一端和一条道路相交(相交一定在中间,不会在道路端点处)。
标记规则:假设街道的向量为(a,b);标记边的向量为(c,d).且c在线段[a,b]上。如果向量(a,b)于向量(c,d)的夹角<=90,则<a,b>方向不可行。反之<a,b>方向可行。
注意:
(1):一条标记边有且且仅标记一条街道。
(2):一条街道可以被多条标记边标记。
(3):街道的端点一定连另外一条或多条街道,不会连标记边。
关键语句:
(1):In general, an end point of a sign touches one and only one line segment representing a street and the other end point is open.
(2):Each end point of every street touches one or more streets, but no signs.
PS.思路很简单,基本上是纯模拟的,但是各种预处理,各种麻烦。做了一晚上,最后终于找出bug,太恶心了。这种几何题吃不消啊。
CODE:
/*几何图上的最短路*/
/*AC代码:32ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <map>
#include <queue>
#include <cmath>
#define INF 1e8
#define eps 1e-6
#define MAXN 605
using namespace std;
struct Node
{
int x,y;
};
struct cmp
{
bool operator()(const Node &a,const Node &b) const
{
if(a.x!=b.x)
return a.x<b.x;
else
return a.y<b.y;
}
};
Node s,e,node[MAXN];
int Map[MAXN][MAXN];
double E[MAXN][MAXN];//最后构建的图
int G[1005][1005];
int deg[MAXN],ans[MAXN];
int pre[MAXN];
double dis[MAXN];
bool vis[MAXN],mark[MAXN];
map<Node,int,cmp>hash;
int cnt;//表示总的点数
int scr,sink,N;
void ini()
{
hash.clear();
memset(Map,0,sizeof(Map));
memset(G,0,sizeof(G));
memset(deg,0,sizeof(deg));
memset(mark,true,sizeof(mark));
cnt=0;
}
int gcd(int n,int m)//求最大公约数
{
if(m==0) return n;
return gcd(m,n%m);
}
int xmulti(Node p1,Node p2,Node p0)//叉积
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int dmulti(Node p1,Node p2)//点积
{
return p1.x*p2.x+p1.y*p2.y;
}
double get_dis(int a,int b)//返回两点距离的平方
{
return sqrt((double)((node[a].x-node[b].x)*(node[a].x-node[b].x)+(node[a].y-node[b].y)*(node[a].y-node[b].y)));
}
int ponls(Node a,Node b,Node p)//判断点p是否在线段a,b上
{
return ((xmulti(b,p,a)==0)&&(((p.x-a.x)*(p.x-b.x)<0)||((p.y-a.y)*(p.y-b.y)<0)));
}
void f(Node now)
{
int i,j;
bool ok=false;
hash[now]=++cnt;
//now.id=cnt;
node[cnt]=now;
for(i=1;i<=cnt&&!ok;i++)
{
for(j=i+1;j<=cnt;j++)
{
if(Map[i][j]&&ponls(node[i],node[j],now))
{
Map[i][j]=Map[j][i]=0;
Map[i][cnt]=Map[cnt][i]=1;
Map[j][cnt]=Map[cnt][j]=1;
deg[cnt]=3;
ok=true;
break;
}
}
}
if(!ok)
{
deg[cnt]=1;
}
}
void Run()
{
int i,dx,dy,nx,ny,w;
Node a,b,c;
scanf("%d%d%d%d",&a.x,&a.y,&b.x,&b.y);
if(!hash[a])
{
f(a);
}
else
deg[hash[a]]++;
if(!hash[b])
{
f(b);
}
else
deg[hash[b]]++;
dx=abs(a.x-b.x);
dy=abs(a.y-b.y);
w=gcd(dx,dy);
dx=(b.x-a.x)/w;
dy=(b.y-a.y)/w;
//遍历所以点,判断是否有点落在新输入的边上(端点除外)
int pre=hash[a];
int after=hash[b];
for(i=1;i<w;i++)
{
nx=a.x+dx*i;
ny=a.y+dy*i;
if(G[nx][ny])
{
c.x=nx;
c.y=ny;
int id=hash[c];
deg[id]+=2;
Map[pre][id]=Map[id][pre]=1;
pre=id;
}
}
Map[pre][after]=Map[after][pre]=1;
G[a.x][a.y]=G[b.x][b.y]=1;
}
int go(int ith,int id,int k)
{
Node p1,p2;
p1.x=node[ith].x-node[id].x;
p1.y=node[ith].y-node[id].y;
p2.x=node[k].x-node[id].x;
p2.y=node[k].y-node[id].y;
int res=dmulti(p1,p2);
//if(res>=0)//表示这个方向行不通
// Map[id][k]=0;
if(res>0) return 1;
if(res==0) return 0;
return -1;
}
int dfs(int pre,int now)
{
int i;
if(mark[now]) return now;
for(i=1;i<=cnt;i++)
{
if(i==pre) continue;
if(Map[now][i]==1 && deg[i]>1)
return dfs(now,i);
}
}
void fuck(int ith)
{
int i,id,a,b;
for(i=1;i<=cnt;i++)
{
if(Map[ith][i]==1&&i!=ith)//处理标记
{id=i;break;}
}
mark[ith]=mark[id]=false;
int k=0;
for(i=1;i<=cnt;i++)
{
if(Map[id][i]==1&&i!=id && deg[i]>1)
{
//注意这里第一个找到的不一定是路的端点,可能是标记端点,所以要递归的找
if(k==0)
{a=dfs(id,i);k++;}
else
{b=dfs(id,i);k++;break;}
//go(ith,id,i);
}
}
//if(k==0) while(1);
int res=go(ith,id,b);
if(res==0)
Map[a][b]=Map[b][a]=-1;
else if(res<0)
{
Map[b][a]=-1;
if(Map[a][b]!=-1)
Map[a][b]=1;
}
else
{
Map[a][b]=-1;
if(Map[b][a]!=-1)
Map[b][a]=1;
}
}
void Build()
{
int i,j;
//先把所有标记点mark为false
for(i=1;i<=cnt;i++)
{
if(deg[i]==1)
{
mark[i]=false;
for(j=1;j<=cnt;j++)
{
if(Map[i][j]==1)
{mark[j]=false;break;}
}
}
}
//遍历所以点,找出度为1的点进行处理
for(i=1;i<=cnt;i++)
{
if(deg[i]==1)
fuck(i);
}
for(i=1;i<=cnt;i++)
{
for(j=1;j<=cnt;j++)
{
if(i==j||!mark[i]||!mark[j]||Map[i][j]==-1||Map[i][j]==0)
E[i][j]=-1;
else
E[i][j]=get_dis(i,j);
}
}
}
queue<int>Q;
void SPFA(int s,int e)//找最短路输出答案
{
int i,u,v,w;
while(!Q.empty()) Q.pop();
memset(vis,false,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(i=1;i<=cnt;i++)
dis[i]=INF;
Q.push(s);
vis[s]=true;
dis[s]=0;
while(!Q.empty())
{
u=Q.front();Q.pop();
vis[u]=false;
for(i=1;i<=cnt;i++)
{
if(E[u][i]==-1) continue;
if(dis[i]>dis[u]+E[u][i])
{
dis[i]=dis[u]+E[u][i];
pre[i]=u;
if(!vis[i])
{
vis[i]=true;
Q.push(i);
}
}
}
}
if(dis[e]==INF)
printf("-1\n");
else
{
int num=0;
u=e;
while(true)
{
ans[num++]=u;
u=pre[u];
if(u==-1) break;
}
for(i=num-1;i>=0;i--)
{
printf("%d %d\n",node[ans[i]].x,node[ans[i]].y);
}
printf("0\n");
}
}
void Print()
{
int i;
for(i=1;i<=cnt;i++)
printf("%d %d\n",node[i].x,node[i].y);
printf("****\n");
}
void Solve()
{
int i;
ini();
scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y);
for(i=1;i<=N;i++)
{
Run();
}
scr=hash[s];
sink=hash[e];
Build();//构图
SPFA(scr,sink);//找最短路
//printf("^%d %d\n",scr,sink);
//Print();
}
int main()
{
while(scanf("%d",&N),N)
{
Solve();
}
return 0;
}
/*
7
0 0 2 3
0 0 3 0
3 0 3 3
3 3 2 3
0 3 2 3
0 0 0 3
1 3 0 4
1 3 2 2
0 0
3 0
3 3
2 3
0
*/
/*
8
0 0 2 3
0 0 3 0
3 0 3 3
3 3 2 3
0 3 2 3
0 0 0 3
1 3 0 4
1 3 2 2
2 2 3 2
0 0
0 3
2 3
0
*/
/*
7
0 0
4 4
0 0 5 0
5 0 5 4
0 0 0 4
0 4 4 4
4 4 5 4
2 4 1 3
3 4 2 3
0 0
0 4
4 4
0
*/