Have you ever played DOTA? If so, you may know the hero, Invoker. As one of the few intelligence carries, Invoker has 10 powerful abilities. One of them is the Ice Wall: Invoker generates a wall of solid ice directly in front of him, and the bitter cold emanating from it greatly slows nearby enemies and deals damage each second.
Now consider the map as a plane. You are now at point s, and want to move to point t. But Invoker has placed N ice walls on the map. Your moving speed is 1 per second, but you need k seconds to pass an ice wall. Time is precious, you must get to point t as quickly as possible. What's the minimum time you need?
For convenience, you can assume that all ice walls are segments (no width) either parallel to X-axis or to Y-axis. Segments are strictly disjoint (have no common point). Point s and t are not on any segment (have no common point).
You will not be slowed when pass the end point of a segment or walk along a segment.
Now consider the map as a plane. You are now at point s, and want to move to point t. But Invoker has placed N ice walls on the map. Your moving speed is 1 per second, but you need k seconds to pass an ice wall. Time is precious, you must get to point t as quickly as possible. What's the minimum time you need?
For convenience, you can assume that all ice walls are segments (no width) either parallel to X-axis or to Y-axis. Segments are strictly disjoint (have no common point). Point s and t are not on any segment (have no common point).
You will not be slowed when pass the end point of a segment or walk along a segment.
Input
The input begins with an integer T, indicating the number of test cases. For each case, the first line is two integers N and k (1 <= N <= 500, 0 <= k <= 10^8), indicating the number of segments and the time needed to pass an ice wall. Next N lines, each have four integers x1, y1, x2, y2, indicating two end points of a segment, (x1, y1) and (x2, y2). Next line has two integers xs and ys, representing the coordinates of starting point s. The last line also has two integers xt and yt, representing the coordinates of target point t. For every point, |x| and |y| <= 108.
Output
For each case, output one line containing the minimum time in second needed to get to t from s. The answer should be given within an absolute or relative error of 10−6.
Sample Input
3 1 1 1 0 1 2 0 0 2 0 1 1 1 -2 1 2 0 0 2 0 1 3 1 -2 1 2 0 0 2 0
Sample Output
2.000000 3.000000 4.472136
这道题还是有些挑战的,可以一眼看出是最短路,但如何处理出点对的直接路径?
考虑极角排序,我不会,就用三角函数的sin和cos代替,然后用bit维护,可以做到N²logN。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <cmath> 6 using namespace std; 7 const double eps=1e-10; 8 const int N=1010,M=4000010; 9 10 struct Node{int x,y,tp;}point[N],s,t,tmp; 11 struct Data{Node t;int id;double k,d;}st[N]; 12 int hsh[2*N],bit[2*N],csh,top;double G[N][N]; 13 14 double Dis(Node a,Node b){ 15 return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y)); 16 } 17 18 double K1(Node b){return 1.0*(b.x-tmp.x)/Dis(tmp,b);} 19 double K2(Node b){return 1.0*(b.y-tmp.y)/Dis(tmp,b);} 20 21 int Rk1(int tp){return tp==4?1:tp==3?3:2;} 22 int Rk2(int tp){return tp==2?1:tp==1?3:2;} 23 24 bool cmp1(Data p,Data q){ 25 Node a=p.t,b=q.t; 26 if(fabs(p.k-q.k)>0)return q.k-p.k>=eps; 27 if(a.tp==4&&b.tp==4)return q.d-p.d>=eps; 28 if(a.tp==3&&b.tp==3)return p.d-q.d>=eps; 29 return Rk1(a.tp)<Rk1(b.tp); 30 } 31 32 bool cmp2(Data p,Data q){ 33 Node a=p.t,b=q.t; 34 if(fabs(p.k-q.k)>0)return p.k<q.k; 35 if(a.tp==2&&b.tp==2)return p.d<q.d; 36 if(a.tp==1&&b.tp==1)return p.d>q.d; 37 return Rk2(a.tp)<Rk2(b.tp); 38 } 39 int Query(int x,int y){int ret=0; 40 x=lower_bound(hsh+1,hsh+csh+1,x)-hsh-1; 41 while(x){ret-=bit[x];x-=x&(-x);} 42 y=lower_bound(hsh+1,hsh+csh+1,y)-hsh; 43 while(y){ret+=bit[y];y-=y&(-y);} 44 return ret; 45 } 46 47 void Add(int x,int d){ 48 x=lower_bound(hsh+1,hsh+csh+1,x)-hsh; 49 while(x<=csh)bit[x]+=d,x+=x&(-x); 50 } 51 52 int tot,n,ice,T; 53 void Solve1(int p){ 54 tmp=point[p];top=0; 55 for(int i=1;i<=tot;i++){ 56 Node b=point[i];if(tmp.y<=b.y)continue; 57 st[++top]=(Data){b,i,K1(b),Dis(tmp,b)}; 58 }sort(st+1,st+top+1,cmp1); 59 memset(bit,0,sizeof(bit)); 60 for(int i=1;i<=top;i++){ 61 Data b=st[i];Node c=b.t; 62 if(c.tp==4)Add(c.y,-1); 63 G[b.id][p]+=ice*Query(c.y,tmp.y); 64 G[p][b.id]+=ice*Query(c.y,tmp.y); 65 if(c.tp==3)Add(c.y,1); 66 } 67 } 68 69 void Solve2(int p){ 70 tmp=point[p];top=0; 71 for(int i=1;i<=tot;i++){ 72 Node b=point[i];if(tmp.x<=b.x)continue; 73 st[++top]=(Data){b,i,K2(b),Dis(tmp,b)}; 74 }sort(st+1,st+top+1,cmp2); 75 memset(bit,0,sizeof(bit)); 76 for(int i=1;i<=top;i++){ 77 Data b=st[i];Node c=b.t; 78 if(c.tp==2)Add(c.x,-1); 79 G[b.id][p]+=ice*Query(c.x,tmp.x); 80 G[p][b.id]+=ice*Query(c.x,tmp.x); 81 if(c.tp==1)Add(c.x,1); 82 } 83 } 84 85 int vis[N];double dis[N]; 86 double Dij(int s,int t){ 87 for(int i=0;i<N;i++) 88 dis[i]=1e20,vis[i]=0;dis[s]=0; 89 for(int i=1,p;i<=tot;i++){p=0; 90 for(int j=1;j<=tot;j++) 91 if(!vis[j]&&dis[p]>dis[j])p=j; 92 vis[p]=true; 93 for(int j=1;j<=tot;j++) 94 dis[j]=min(dis[j],dis[p]+G[p][j]); 95 } 96 return dis[t]; 97 } 98 99 void Initial(){ 100 memset(G,0,sizeof(G)); 101 tot=csh=0; 102 } 103 104 int main(){ 105 scanf("%d",&T); 106 while(T--){ 107 scanf("%d%d",&n,&ice);Initial(); 108 for(int i=1,x1,y1,x2,y2;i<=n;i++){ 109 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 110 hsh[++csh]=x1;hsh[++csh]=x2; 111 hsh[++csh]=y1;hsh[++csh]=y2; 112 if(x1==x2&&y1==y2)continue; 113 if(x1==x2){ 114 if(y1>y2)swap(y1,y2); 115 point[++tot]=(Node){x1,y1,1}; 116 point[++tot]=(Node){x2,y2,2}; 117 } 118 if(y1==y2){ 119 if(x1>x2)swap(x1,x2); 120 point[++tot]=(Node){x1,y1,3}; 121 point[++tot]=(Node){x2,y2,4}; 122 } 123 } 124 125 scanf("%d%d",&s.x,&s.y); 126 scanf("%d%d",&t.x,&t.y); 127 128 hsh[++csh]=s.x;hsh[++csh]=s.y; 129 hsh[++csh]=t.x;hsh[++csh]=t.y; 130 131 sort(hsh+1,hsh+csh+1); 132 csh=unique(hsh+1,hsh+csh+1)-hsh-1; 133 134 point[++tot]=(Node){s.x,s.y,0}; 135 point[++tot]=(Node){t.x,t.y,0}; 136 137 for(int i=1;i<=tot;i++)Solve1(i); 138 for(int i=1;i<=tot;i++)Solve2(i); 139 140 for(int i=1;i<=tot;i++) 141 for(int j=1;j<=tot;j++) 142 G[i][j]+=Dis(point[i],point[j]); 143 printf("%.6lf ",Dij(tot-1,tot)); 144 } 145 return 0; 146 }
WA在求dis的平方上了,注意会爆int。
附上数据生成器:
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <ctime> 7 using namespace std; 8 int G[1010][1010],h[1010]; 9 int main(){ 10 srand(time(NULL)); 11 int T=1,n=500,w=1000; 12 printf("%d ",T); 13 while(T--){ 14 printf("%d %d ",n,rand()%w); 15 int x,y,a,b,l; 16 for(int i=0;i<w;i++){ 17 h[i]=rand()*rand()%100000000; 18 if(rand()%2)h[i]*=-1; 19 } 20 sort(h,h+w); 21 memset(G,0,sizeof(G)); 22 for(int i=1;i<=n;i++){ 23 while(true){ 24 x=rand()%w;y=rand()%w; 25 while(G[x][y])x=rand()%w,y=rand()%w; 26 if(rand()%2){ 27 a=x;l=0; 28 while(y+l+1<=w&&G[x][y+l]==0)l++; 29 if(l==1)continue;b=y+rand()%(l-1)+1; 30 } 31 else{ 32 b=y;l=0; 33 while(x+l+1<=w&&G[x+l][y]==0)l++; 34 if(l==1)continue;a=x+rand()%(l-1)+1; 35 } 36 for(int j=x;j<=a;j++) 37 for(int k=y;k<=b;k++) 38 G[j][k]=1; 39 printf("%d %d %d %d ",h[x],h[y],h[a],h[b]); 40 break; 41 } 42 } 43 x=rand()%w;y=rand()%w; 44 while(G[x][y])x=rand()%w,y=rand()%w; 45 printf("%d %d ",h[x],h[y]);G[x][y]=1; 46 x=rand()%w;y=rand()%w; 47 while(G[x][y])x=rand()%w,y=rand()%w; 48 printf("%d %d ",h[x],h[y]); 49 } 50 return 0; 51 }