思路分析:
解法一:
由于这道题提到可能有负权边,那么dijsktra算法肯定首先就被我们排除了,floyd?想都不要想,最后我们只剩下了Spfa,但众所周知,USACO是卡Spfa的,但似乎没有其他的解法了,于是我们就可以像一道最短路板子题一样建图,从起点出发,跑一遍Spfa,交上去,果不其然,TLE掉了两个点。但也只有两个点,于是我们想到用SLF去优化它,所谓SLF,就是在Spfa入队时拿将要入队的数和队首元素比较,如果比队首元素小则插入队首,否则插在対尾,于是用到双端队列,每次入队前判断一下就好了。这样我们就可以在开O2的前提下水过这道题了,但不开O2还是会TLE掉一个点,其实这道题只是不想卡SLF,但SLF优化并没有基于复杂度,实际上可以构造数据来卡到2^n,甚至可能比普通spfa更慢(以上一句话来自洛谷大佬(id:1010_)),但既然能过,也是一种方法。
上代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 #define debug printf("------------\n"); 7 const int N=1e6+10; 8 int Head[N],tot,T,P,R,S,dis[N],vis[N]; 9 struct Node{ 10 int next,to,dis; 11 }edge[N]; 12 void Add(int x,int y,int z){ 13 edge[++tot].to=y; 14 edge[tot].next=Head[x]; 15 edge[tot].dis=z; 16 Head[x]=tot; 17 } 18 void Spfa(int x){ 19 memset(dis,0x3f,sizeof(dis)); 20 memset(vis,0,sizeof(vis)); 21 deque<int>q; //只有这里不同,其他都是板子 22 q.push_back(x);vis[x]=1;dis[x]=0; 23 while(!q.empty()){ 24 int u=q.front();q.pop_front(); 25 for(int i=Head[u];i;i=edge[i].next){ 26 int v=edge[i].to;vis[u]=0; 27 if(dis[v]>dis[u]+edge[i].dis){ 28 dis[v]=dis[u]+edge[i].dis; 29 if(!vis[v]){ 30 if(!q.empty()&&dis[v]>=dis[q.front()]) 31 q.push_back(v); 32 else q.push_front(v); 33 vis[v]=1; 34 } 35 } 36 } 37 } 38 } 39 int main(){ 40 // freopen("a.txt","r",stdin); 41 // freopen("my.txt","w",stdout); 42 scanf("%d%d%d%d",&T,&R,&P,&S); 43 for(int i=1;i<=R;++i){ 44 int x,y,z; 45 scanf("%d%d%d",&x,&y,&z); 46 Add(x,y,z);Add(y,x,z); 47 } 48 for(int i=1;i<=P;++i){ 49 int x,y,z; 50 scanf("%d%d%d",&x,&y,&z); 51 Add(x,y,z); 52 } 53 Spfa(S); 54 for(int i=1;i<=T;++i){ 55 if(dis[i]==0x3f3f3f3f) 56 printf("NO PATH\n"); 57 else printf("%d\n",dis[i]); 58 } 59 return 0; 60 }