Party

Party

Time Limits: 1000 ms Memory Limits: 65536 KB

Description
  N头牛要去参加一场在编号为x(1<=x<=n)的牛的农场举行的派对(1<=N<=1000),有M(1<=m<=100000)条有向道路,每条路长ti(1<=ti<=100);
  每头牛都必须参加完派对后回到家,每头牛都会选择最短路径,求这n个牛的最短路径(一个来回)中最长的一条的长度。
  特别提醒:可能有权值不同的重边。

Input
  第1行: N,M,X;
  第2~m+1行: Ai,Bi,Ti,表示有一条从Ai到Bi的路,长度为Ti.

Output
  最长最短路的长度。

Sample Input

4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3

Sample Output

10

Hint
【样例说明】
说明


解题思路

一看就应该知道是SPFA,而不用Floyd,亏某位刘某昊同学还用Floyd骗了80。

存一组边,另一组存反过来的边,以Party的位置开始SPFA,两次分别求出去世的最短路径和回时的最短路径,再求答案即可。

#include<cstring>
#include<cstdio>
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;

int Groad[100001][4],Broad[100001][4],Gfir[1001],Glas[1001],Bfir[1001],Blas[1001],fg[1001],fb[1001],data[400000];
bool bz[1001];

void GetThere(int);
void GetHere(int);
void insert(int,int,int,int);

int main()
{
    memset(fb,0x7f,sizeof(fb));
    memset(fg,0x7f,sizeof(fg));
    int n,m,x,ans=0;
    scanf("%d%d%d",&n,&m,&x);
    fo(i,1,m)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        insert(i,a,b,c);
    }
    GetHere(x);GetThere(x);
    fo(i,1,n)ans=max(ans,fg[i]+fb[i]);
    printf("%d",ans);
}

void insert(int p,int x,int y,int z)
{
    Groad[p][0]=x;Groad[p][1]=y;Groad[p][2]=z;Groad[p][3]=p;
    Broad[p][0]=y;Broad[p][1]=x;Broad[p][2]=z;Broad[p][3]=p;
    if(Gfir[x]==0)Gfir[x]=p; else Groad[Glas[x]][3]=p;
    if(Bfir[y]==0)Bfir[y]=p; else Broad[Blas[y]][3]=p;
    Glas[x]=Blas[y]=p;
}

void GetThere(int s)
{
    int h=0,t=1;
    data[1]=s;
    memset(bz,1,sizeof(bz));
    bz[s]=0;fg[s]=0;
    while(h<t)
    {
        h++;
        int now=data[h],v=fg[now],o=Gfir[now];
        if(o<1)continue;
        while(1)
        {
            int x=Groad[o][1],va=v+Groad[o][2];
            if(va<fg[x])
            {
                fg[x]=va;
                if(bz[x])
                {
                    bz[x]=0;
                    t++;
                    data[t]=x;
                }
            }
            if(o==Groad[o][3])break;
            o=Groad[o][3];
        }
        bz[now]=1;
    }
}

void GetHere(int s)
{
    int h=0,t=1;
    data[1]=s;
    memset(bz,1,sizeof(bz));
    bz[s]=0;fb[s]=0;
    while(h<t)
    {
        h++;
        int now=data[h],v=fb[now],o=Bfir[now];
        if(o<1)continue;
        while(1)
        {
            int x=Broad[o][1],va=v+Broad[o][2];
            if(va<fb[x])
            {
                fb[x]=va;
                if(bz[x])
                {
                    bz[x]=0;
                    t++;
                    data[t]=x;
                }
            }
            if(o==Broad[o][3])break;
            o=Broad[o][3];
        }
        bz[now]=1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值