[SDOI2009]Elaxia的路线
下面的做法虽然能通过此题数据,但其实是错误的。请有兴趣的读者自行研究该算法的错误在哪里。
思路:
标算是跑四趟SPFA,然后拓扑排序求最长链。
我的做法是对于两个起点、终点分别跑一个Dijkstra,然后枚举每个点对,判断是否都在最短路上,并对其距离取$max$。
BZOJ上跑了440ms,内存6556KB,代码长度1906B,比标算不知miao到哪里去了。
1 #include<cstdio> 2 #include<cctype> 3 #include<functional> 4 #include<ext/pb_ds/priority_queue.hpp> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int inf=0x7fffffff; 13 const int V=1501; 14 struct Edge { 15 int to,w; 16 }; 17 std::vector<Edge> e[V]; 18 inline void add_edge(const int u,const int v,const int w) { 19 e[u].push_back((Edge){v,w}); 20 } 21 struct Vertex { 22 int id,dis; 23 bool operator > (const Vertex &another) const { 24 return dis>another.dis; 25 } 26 }; 27 int n,s1,t1,s2,t2; 28 int ds1[V],dt1[V],ds2[V],dt2[V]; 29 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; 30 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[V]; 31 inline void Dijkstra(const int s,int *dis) { 32 q.clear(); 33 for(int i=1;i<=n;i++) { 34 p[i]=q.push((Vertex){i,dis[i]=(i==s?0:inf)}); 35 } 36 while(q.top().dis!=inf) { 37 int x=q.top().id; 38 for(unsigned i=0;i<e[x].size();i++) { 39 Edge &y=e[x][i]; 40 if(dis[x]+y.w<dis[y.to]) { 41 q.modify(p[y.to],(Vertex){y.to,dis[y.to]=dis[x]+y.w}); 42 } 43 } 44 q.modify(p[x],(Vertex){x,inf}); 45 } 46 } 47 inline bool check(const int x) { 48 return (ds1[x]+dt1[x]==ds1[t1])&&(ds2[x]+dt2[x]==ds2[t2]); 49 } 50 int main() { 51 n=getint(); 52 int m=getint(); 53 s1=getint(),t1=getint(),s2=getint(),t2=getint(); 54 for(int i=0;i<m;i++) { 55 int u=getint(),v=getint(),w=getint(); 56 add_edge(u,v,w); 57 add_edge(v,u,w); 58 } 59 Dijkstra(s1,ds1); 60 Dijkstra(t1,dt1); 61 Dijkstra(s2,ds2); 62 Dijkstra(t2,dt2); 63 int ans=0; 64 for(int i=1;i<=n;i++) { 65 if(!check(i)) continue; 66 for(int j=i+1;j<=n;j++) { 67 if(!check(j)) continue; 68 ans=std::max(ans,std::abs(ds1[i]-ds1[j])); 69 } 70 } 71 printf("%d\n",ans); 72 return 0; 73 }
后来把vector改成了数组,跑了436ms,只快了一点点,然而内存翻了三倍。
1 #include<cstdio> 2 #include<cctype> 3 #include<functional> 4 #include<ext/pb_ds/priority_queue.hpp> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int inf=0x7fffffff; 13 const int V=1501; 14 struct Edge { 15 int to,w; 16 }; 17 Edge e[V][V]; 18 int sz[V]={0}; 19 inline void add_edge(const int u,const int v,const int w) { 20 e[u][sz[u]++]=(Edge){v,w}; 21 } 22 struct Vertex { 23 int id,dis; 24 bool operator > (const Vertex &another) const { 25 return dis>another.dis; 26 } 27 }; 28 int n,s1,t1,s2,t2; 29 int ds1[V],dt1[V],ds2[V],dt2[V]; 30 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; 31 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[V]; 32 inline void Dijkstra(const int s,int *dis) { 33 q.clear(); 34 for(int i=1;i<=n;i++) { 35 p[i]=q.push((Vertex){i,dis[i]=(i==s?0:inf)}); 36 } 37 while(q.top().dis!=inf) { 38 int x=q.top().id; 39 for(int i=0;i<sz[x];i++) { 40 Edge &y=e[x][i]; 41 if(dis[x]+y.w<dis[y.to]) { 42 q.modify(p[y.to],(Vertex){y.to,dis[y.to]=dis[x]+y.w}); 43 } 44 } 45 q.modify(p[x],(Vertex){x,inf}); 46 } 47 } 48 inline bool check(const int x) { 49 return (ds1[x]+dt1[x]==ds1[t1])&&(ds2[x]+dt2[x]==ds2[t2]); 50 } 51 int main() { 52 n=getint(); 53 int m=getint(); 54 s1=getint(),t1=getint(),s2=getint(),t2=getint(); 55 for(int i=0;i<m;i++) { 56 int u=getint(),v=getint(),w=getint(); 57 add_edge(u,v,w); 58 add_edge(v,u,w); 59 } 60 Dijkstra(s1,ds1); 61 Dijkstra(t1,dt1); 62 Dijkstra(s2,ds2); 63 Dijkstra(t2,dt2); 64 int ans=0; 65 for(int i=1;i<=n;i++) { 66 if(!check(i)) continue; 67 for(int j=i+1;j<=n;j++) { 68 if(!check(j)) continue; 69 ans=std::max(ans,std::abs(ds1[i]-ds1[j])); 70 } 71 } 72 printf("%d\n",ans); 73 return 0; 74 }
洛谷上跑出来152ms,Rank3。Rank2的做法是Dijkstra+拓扑排序。Rank1怎么跑这么快?