SPFA的运用

来源:互联网 发布:shopwwi 统计无数据 编辑:程序博客网 时间:2024/05/22 07:46

题目描述:

给你一个n,表示有n个点。再给你四个点,分别是s1,s2,t1,t2。前面两个分别表示的是两个起点,后面两个分别表示的是两个终点。然后给你一个m,表示有m条边,分别给你m条边。这些边可能有重边,但数据保证无环。然后题目是要求的分别从s1到t1和s2到t2的最短路上最长的交集。

样例输入
8 10
3 6 8 6
6 2 3
3 7 3
8 4 7
7 4 8
7 8 8
3 2 3
3 4 4
8 7 3
5 3 3
5 3 3
样例输出:
6
本题解法:
对于上述4个点跑一边SPFA,然后在判断一下。具体怎么判断在代码中解释。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<deque>#define max(a,b) (a>b?a:b)#define inf 0x3f3f3f#define fp(i,a,b) for(register int i=a;i<=b;++i)using namespace std;typedef int Node[1505];struct arr{    int nd,nx,co;}bot[5250010];int head[2000],vis[2000];int n,m,cnt,s1,s2,t1,t2,ans;Node S1,T1,S2,T2;inline int read(){    int x=0,w=1;char ch=0;    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();    if(ch=='-') w=-1,ch=getchar();    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();    return x*w;}inline void add(int a,int b,int c){bot[++cnt].nd=b;bot[cnt].co=c;bot[cnt].nx=head[a];head[a]=cnt;}inline void SPFA(int s,int *dis){    fp(i,1,n) dis[i]=inf;dis[s]=0;vis[s]=0;    deque<int> q;q.push_back(s);    while(!q.empty()){        int u=q.front(),v;q.pop_front();vis[u]=0;        for(register int i=head[u];i;i=bot[i].nx)            if(dis[v=bot[i].nd]>dis[u]+bot[i].co){                dis[v]=dis[u]+bot[i].co;                if(!vis[v]){                    if(q.empty()||dis[v]>dis[q.front()]) q.push_back(v);                    else q.push_front(v);                    vis[v]=1;                }            }    }}inline int check(int x){return S1[x]+T1[x]==S1[t1]&&S2[x]+T2[x]==S2[t2]; }//这里就是那个check,如果s1到x的距离+t1到x的距离等于s1到t1的距离,则在最短路上,并且要在另一条最短路上inline int maxx(int a,int b){return a<b?b:a;}int main(){    freopen("together.in ","r",stdin);    freopen("together.out","w",stdout);    n=read();m=read();s1=read();t1=read();s2=read();t2=read();    fp(i,1,m) {int u=read(),v=read(),w=read(); add(u,v,w);add(v,u,w);   }     SPFA(s1,S1);SPFA(s2,S2);SPFA(t1,T1);SPFA(t2,T2);//在这里记录下了从各4个点出发的单源最短路    fp(i,1,n)  if(check(i)) fp(j,i+1,n)  if(check(j))  ans=max(ans,abs(S1[i]-S1[j])); //这里有几个if主要是判断这两个点是不是在这两条最短路的公共上。最后得答案就直接算出i到j的距离即可。    printf("%d",ans);    return 0;               }

下面是出题人的代码(莫名其妙的我按照出题人的代码打,结果时间多了一倍左右)

#include<deque>#include<cstdio>#define re register int#define fp(i,a,b) for(re i=a,I=b;i<=I;++i)#define chkmax(a,b) (a<b?a=b:0)#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)using namespace std;char ss[1<<17],*A=ss,*B=ss;inline char gc(){if(A==B){B=(A=ss)+fread(ss,1,1<<17,stdin);if(A==B)return EOF;}return*A++;}template<class T>inline void sdf(T&x){    char c;re y=1;while(c=gc(),c<48||57<c)if(c=='-')y=-1;x=c^48;    while(c=gc(),47<c&&c<58)x=(x<<1)+(x<<3)+(c^48);x*=y;}const int N=1505,M=2250010,inf=1e9;typedef int arr[N];struct edges{int nx,to,w;}e[M<<1];int n,m,s1,s2,t1,t2,tot,ans;arr S1,S2,T1,T2,fi,vis;inline int abs(const re&a){return a<0?-a:a;}inline void add(re u,re v,re w){e[++tot]=(edges){fi[u],v,w};fi[u]=tot;}inline void spfa(re s,re*dis){    fp(i,1,n)dis[i]=inf,vis[i]=0;dis[s]=0;    deque<int>q;q.push_back(s);re u,v;    while(!q.empty()){        u=q.front();q.pop_front();vis[u]=0;        for(re i=fi[u];i;i=e[i].nx)            if(dis[v=e[i].to]>dis[u]+e[i].w){                dis[v]=dis[u]+e[i].w;                if(!vis[v]){                    if(q.empty()||dis[v]>dis[q.front()])q.push_back(v);                    else q.push_front(v);                    vis[v]=1;                }            }    }}inline int chk(re x){return S1[x]+T1[x]==S1[t1]&&S2[x]+T2[x]==S2[t2];}int main(){    file("together");     sdf(n);sdf(m);sdf(s1),sdf(t1);sdf(s2),sdf(t2);    fp(i,1,m){re u,v,w;sdf(u),sdf(v),sdf(w);add(u,v,w),add(v,u,w);}    spfa(s1,S1),spfa(t1,T1),spfa(s2,S2),spfa(t2,T2);    fp(i,1,n)if(chk(i))fp(j,i+1,n)if(chk(j))chkmax(ans,abs(S1[i]-S1[j]));    printf("%d",ans);return 0;}

反思:

这说明对SPFA的一些性质和用法还不太熟悉,并且思维还不到位,考场时往这方面想了,但是最后并没想出,所以还得多加训练。

在这里给出一下,这位大佬出的这道题的题面

在一起(together)
【题目背景】
那时很天真, PP 以为能在人海中相遇、 相识 BB 就是厮守一生的缘分。 怎料
他们都被命运捉弄了, 只能是过客。 如果不能在一起, 何必当初相识?倒不如擦
肩而过, 从不相遇。
一次邂逅, 是命运的恩赐。 我们在人海中遇到彼此, 不过寥寥数语中就拨动
了我的心弦。 这短暂的相遇在我的心中种下了一颗名为“爱情” 的种子, 我用思
念、 期待给予它养分, 想象它萌芽的瞬间, 想象它盛开的娇艳, 想象它结果的美
好。
想象越是美好, 现实就越是残忍。 PP 一次次地在曾和 BB 相遇的地方(那充
满美好回忆的高中校园) 等待, 只为再一次偶遇, 能够让心中的种子得到更多生
根发芽的养分。 只可惜, 高中校园实在太大, 一共有 n 个地点。 期待一次次落空,
都没能阻止 PP 的等候。 当 PP 在拥挤的人群中看到 BB 的身影时, PP 以为这是上
天对自己的另一个恩赐, 却在下一秒把这个礼物变成了利器, 刺痛了 PP 的心,
变成了一场飓风, 带走了还没来得及发芽的种子。 因为校园实在是有太多路径了
(m 条) , 每条路还有自己的长度, 而且还可以在路径两端来来往往, 所以他们
想相遇都非常难。 顷刻间, 似乎一切都是一场梦, PP 和 BB 仿佛从未相遇、 相识,
PP 对 BB 仿佛从来没有恋慕, 他们依旧只是陌生人。
然而, PP 很清楚, 那如梦的邂逅是命运的玩笑。 PP 的爱情还来不及真正开
始就已经默默结束了, 看着 BB 在人群中紧紧地拥着他的肩, 脸上露出让 PP 陌生
的温柔微笑, 完全没有注意到即将和你擦肩而过的 PP。 PP 知道自己和 BB 总是在
教室和宿舍之间徘徊, 而他们之间路径的交集似乎并不是很多。 这一刻, PP 知
道梦该醒了, 只是如果不能在一起, 何必当初相识, 让 PP 做了一场美梦, 最后
却要无情地打碎这个梦。
PP 走在教室和宿舍之间的最短路上, 偶然看到了 BB, 后来 PP 才了解到 BB
也是只会走最短路的。 PP 想要转身离开, 假装没有看见 BB, 但 PP 更想假装从未
见过 BB, 从未对 BB 心动。 可是 PP 无法移动双脚, 依然默默地看着 BB 远去的身
影, 仿佛想要让曾经的美梦破碎得更加彻底, 最好能够让 PP 就此遗忘, 再也不
会想起。 可是 PP 依然清楚地记得他们说过的每一句话, PP 对 BB 说的最后一句
话是“再见” 。 现在他们如愿再见了, 但是 PP 宁愿自己当初对 BB 说的是“不再
见” , 然后这辈子再也没有交集, 可是 PP 并不甘心, 就算能多看到 BB 几眼对
PP 来说也是十分幸福的, 所以 PP 经过不懈努力, 终于了解到了 BB 的往返路径。
对着 BB 的背影, PP 说不出再见。 PP 就这样看着 BB 走出 PP 的视线, PP 心里
想着要是能知道自己和 BB 往返路径的交集最长是多少就好了, 交集顾名思义就
是 PP 和 BB 往返路径的公共路径, 这样 PP 就能规划好时间, 多看 BB 几眼了。 PP
只是 BB 生命中一个微不足道的过客, 而 PP 已经把 BB 写进自己的未来。 但是他
们之间没有未来, 只有曾经。 也许有一天时过境迁的时候, PP 会忘记和 BB 匆匆
的相识, 因为不想记起, 也不敢记起。 一旦想起, PP 害怕自己会不再相信缘分,躲避所有可能的幸福, 用孤单惩罚自己曾经的天真。
人群渐渐散去, PP 依然站在原地, 看着 BB 离去的方向。 PP 终于有力气转身
离开, 一边走一边疑惑: 如果不能在一起, 何必当初相识?或许这是命运的善良,让 PP 不再天真;或许这是命运的残忍, 让 PP 看清现实。 不是所有相遇都能有圆
满的结局, 总会有不尽如人意的结尾, 不是所有美梦都能成真, 总会有梦碎的时
刻。 PP 终于明白了, 应该放下 BB 了, 愿在 PP 放下的瞬间, 属于 PP 的幸福还没
有停止寻找他, 从相遇开始一直到老都不分离。

【输入格式】
从文件 together.in
中读入数据。
输入的第一行两个整数 n,m;n,m 含义如题目描述。
输入的第二行四个整数 x1,y1,x2,y2,分别表示 PP 的寝室和教室及 BB 的寝
室和教室的标号。
接下来 m 行, 每行三个整数,u,v,w,表 u 和 v 之间有一条路, 经过这条路长
度为 w, 即通过这条路的时间。
同一行输入的相邻两个元素之间, 用恰好一个空格隔开。
【输出格式】
输出到文件 together..out 中。
输出包括一行表示 PP 和 BB 的路径最长交集长度
【样例输入】
8 10
3 6 8 6
6 2 3
3 7 3
8 4 7
7 4 8
7 8 8
3 2 3
3 4 4
8 7 3
5 3 3
5 3 3
【样例输出】
6
【子任务】
x1,y1,x2,y2∈[1,n]
w∈[1,10000]
数据保证没有自环, 不保证没重边
测试点编号 n<= m<= 时限
1 10 100 0.1s
2 20 400 0.1s
3 50 2500 0.1s
4 80 6400 0.2s
5 100 10000 0.3s
6 233 54289 0.3s
7 444 197136 0.5s
8 500 250000 0.5s
9 600 360000 0.5s
10 666 443556 1s
11 700 490000 1s
12 888 788544 1s
13 900 810000 1s
14 1000 1000000 1s
15 1100 1210000 1.3s
16 1111 1234321 1.3s
17 1212 1468944 1.5s
18 1314 1726596 1.5s
19 1421 2019241 2s
20 1500 2250000 2.3s

原创粉丝点击