P3008 [USACO11JAN]道路和飞机Roads and Planes
P3008 [USACO11JAN]道路和飞机Roads and Planes
Dijkstra+Tarjan
因为题目有特殊限制所以不用担心负权的问题
但是朴素的Dijkstra就算用堆优化,也显然会超时。
这是因为Dj每次扩展时,总是找到费用最小那个点进行扩展。
而本题的毒瘤数据可以在一个图(设其点数为k)后连一长串负权边。这样每次扩展的最坏复杂度O(n^k),T出天际。
但是我们又可以用到题目的特殊限制:一个图被限制成若干层,每层的最短路互相无影响。
显然,我们可以用Tarjan缩点法,把图分层,把每层分离出来,单独跑一遍Dj。
然后就没了。(逃
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cctype> using namespace std; template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;} template <typename T> inline void read(T &x){ char c=getchar(); x=0; bool f=1; while(!isdigit(c)) f= !f||c=='-' ? 0:1,c=getchar(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); x= f? x:-x; } int n,m1,m2,s,d[25002],cnt1,hd[25002],nxt[150002],ed[25002],poi[150002],val[150002]; int dfs_clock,cnt2,_top,low[25002],dfn[25002],be[25002],st[25002]; //用于Tarjan struct data{ int d,u; bool operator < (const data &tmp) const { if(be[u]!=be[tmp.u]) return be[u]<be[tmp.u]; //同块内先处理 return d>tmp.d; } }; priority_queue <data> h; inline void add(int x,int y,int v){ nxt[ed[x]]=++cnt1; hd[x]= hd[x] ? hd[x]:cnt1; ed[x]=cnt1; poi[cnt1]=y; val[cnt1]=v; } inline void tarjan(int x){ //Tarjan模板,可右转P3387 dfn[x]=low[x]=++dfs_clock; st[++_top]=x; for(int i=hd[x];i;i=nxt[i]){ int to=poi[i]; if(!dfn[to]) tarjan(to),low[x]=min(low[x],low[to]); else if(!be[to]) low[x]=min(low[x],dfn[to]); } if(low[x]==dfn[x]){ //给出每个点所处层的编号 be[x]=++cnt2; while(st[_top]!=x) be[st[_top--]]=cnt2; --_top; } } void dijkstra(){ //裸的 memset(d,127,sizeof(d)); h.push((data){d[s]=0,s}); while(!h.empty()){ data x=h.top(); h.pop(); if(x.d!=d[x.u]) continue; for(int i=hd[x.u];i;i=nxt[i]) if(x.d+val[i]<d[poi[i]]){ d[poi[i]]=x.d+val[i]; h.push((data){d[poi[i]],poi[i]}); } } } int main(){ read(n); read(m1); read(m2); read(s); int q1,q2,q3; for(int i=1;i<=m1;++i) read(q1),read(q2),read(q3),add(q1,q2,q3),add(q2,q1,q3); for(int i=1;i<=m2;++i) read(q1),read(q2),read(q3),add(q1,q2,q3); tarjan(s); //tarjan缩点 for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); dijkstra(); for(int i=1;i<=n;++i){ if(d[i]==d[0]) printf("NO PATH\n"); else printf("%d\n",d[i]); }return 0; }