题目大意:
给你一幅图,上面有一些“街道”和“标记边”组成。问你某两点之间的最短路径。(“标记边”用来规定“街道”的方向)。
街道:表示两点之间有边相连。
标记边:标记边的一端悬空,令一端和一条道路相交(相交一定在中间,不会在道路端点处)。
标记规则:假设街道的向量为(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 */