【2018.3.10】模拟赛之四-ssl2133 腾讯大战360【SPAF,图论,最短路径】

目录地址

前言

打错了一个地方之接60,还有输出“Peace”能拿60。还有题目坑爹害得我用了哈希,可以无视 QAQ


正题

有一个n*n的图,有m条边,不知道几个城市,给出两个位置,求两个位置移动到相遇(不能再路上)的最短路径。


输入输出(需要自取)

Input

输入数据第一行:N和M(用空格隔开) 表示这是一个N*N的图并且有M条边,第二行到第M+1行 为这个图的详细信息。
每行共有被空格隔开的三个数:a b c。表示编号为a的城市到编号为b的城市
有一个双向边,并且要过这条双向边所需要花费的时间为c。
最后一行有两个数:S和T,S表示腾讯所处的城市(也就是深圳),T表示360所处的
城市(也就是北京)

Output

输出只有一行,D,表示二者“相遇”的最短时间。当然,如果无法相遇则输出“Peace!”

Sample Input

3 3
1 2 1
2 3 1
1 3 1
1 3

Sample Output

1


解题思路

两遍SPFA,然后枚举相遇点。无视哈希


代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int p=29989,air=-117901064;
struct woc{
    int x,y,w,next;
};
int n,m,sum,f[p+1],ls[p+1],f2[p+1],hash[p+1],state[p+1],head,tail,num;
bool v[p+1];
woc line[10001];
int hashmath(int x)
{
    return abs(x)%p;
}
int locate(int x)
{
    int wz=hashmath(x);
    int i=0;
    while (i<p && hash[(wz+i)%p]!=x && hash[(wz+i)%p]!=air)
      i++;
    return (wz+i)%p;
}
void Spfa(int x)//SPFA不解释
{
    memset(f,127/3,sizeof(f));
    state[1]=locate(x);v[state[1]]=true;f[state[1]]=0;
    int w=0;
    head=0;tail=1;
    do
    {
        head=head%p+1;
        w=ls[state[head]];
        while (w!=0)
        {
            if (f[line[w].x]+line[w].w<f[line[w].y])
            {
                f[line[w].y]=f[line[w].x]+line[w].w;
                if (!v[line[w].y])
                {
                    v[line[w].y]=true;
                    tail=tail%p+1;
                    state[tail]=line[w].y;
                }
            }
            w=line[w].next;
        }
        v[state[head]]=false;
    }
    while (head!=tail);
}
void Spfa2(int x)
{
    memset(f2,127/3,sizeof(f2));
    state[1]=locate(x);v[state[1]]=true;f2[state[1]]=0;
    int w=0;
    head=0;tail=1;
    do
    {
        head=head%p+1;
        w=ls[state[head]];
        while (w!=0)
        {
            if (f2[line[w].x]+line[w].w<f2[line[w].y])
            {
                f2[line[w].y]=f2[line[w].x]+line[w].w;
                if (!v[line[w].y])
                {
                    v[line[w].y]=true;
                    tail=tail%p+1;
                    state[tail]=line[w].y;
                }
            }
            w=line[w].next;
        }
        v[state[head]]=false;
    }
    while (head!=tail);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<p;i++) hash[i]=air;
    int xx,yy,ww,wz1,wz2;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&xx,&yy,&ww);
        wz1=locate(xx);wz2=locate(yy);
        if (hash[wz1]==air) hash[wz1]=xx;
        if (hash[wz2]==air) hash[wz2]=yy;
        line[++num].x=wz1;
        line[num].y=wz2;
        line[num].w=ww;
        line[num].next=ls[wz1];
        ls[wz1]=num;
        line[++num].x=wz2;
        line[num].y=wz1;
        line[num].w=ww;
        line[num].next=ls[wz2];
        ls[wz2]=num;//无向图建邻接表
    }
    scanf("%d%d",&xx,&yy);
    Spfa(xx);
    Spfa2(yy);//两遍SPFA
    sum=-air;
    for (int i=0;i<p;i++)//枚举相遇点
    {
        if (hash[i]!=air)
        {
            sum=min(sum,max(f[i],f2[i]));//更新最大值
        }
    }
    if (sum==-air) printf("Peace!");//判断无法相遇
    else printf("%d",sum);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值