POJ-1511(SPFA找最短路(正向和反向))

///这个题目有点意思,搞了很久过了的样例,后来发现全部都白做了,一直RE RE ,一首fuck送给题目;
///说说这个题目吧,就是求1节点到所给任意节点的最短路径之和ans1,再求任意除1节点外的节点到1节点(反向)的最短距离之和ans2;ans=ans1+ans2;
///那为什么我发现全白做了呢,因为我用的是dijkstra,它们给我的节点的个数是1e6,瞬间就傻逼了;
///那么这个题就好做多了,无意间发现前向星是一个好东西,说白了就是数组对领接表的一个优化;所以加上SPFA就可以求两次的最短路了(前向闪现,反向开大);
///核心:SPFA+领接表的优化;(土鳖邻接矩阵版本肯定是不能做的)
///这个是我第一个领接表的写法,所以这个得好好的详细的解说一下了;
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;

const int  inf=0x3f3f3f3f;
const int maxn=1e6+7;
int  head[maxn],n,m;
long long dis[maxn];

struct node
{
    int to,w,next;///分别表示:终点,权值,最重要的形成表的一个东西,就是当前节点与下一条边的储存位置(箭头指向上一个节点就OK了);
}eage[maxn];

void Add(int top,int u,int v,int w)
{
    eage[top].to=v;
    eage[top].w=w;
    eage[top].next=head[u];
    head[u]=top;
    ///-1<-0<-1<-2;类似于形成一个这样的东西,再遍历的时候只需要判断i是不是-1就完美了(后来慢慢的看着就像是领接数组);
}

long long SPFA()
{
    memset(dis,inf,sizeof(dis));
    queue<int>Q;
    Q.push(1);
    dis[1]=0;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for(int i=head[u];i!=-1;i=eage[i].next)
        {
            int v=eage[i].to;
            if(dis[v]>dis[u]+eage[i].w)
            {
                dis[v]=dis[u]+eage[i].w;
                Q.push(v);
            }
        } ·
    }
    long long ans=0;
    for(int i=1;i<=n;i++)
        ans+=dis[i];///记录两次最短路之和;
    return ans;
}

int main ()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        memset(head,-1,sizeof(head));///一般来说,head的初始值都赋值为-1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d %d",&a1[i],&a2[i],&a3[i]);
            Add(i,a1[i],a2[i],a3[i]);///先顺着建立领接表。
        }
        long long ans=SPFA();
        memset(head,-1,sizeof(head));
        for(int i=1;i<=m;i++)
            Add(i,a2[i],a1[i],a3[i]);///再次建表,反向得到每个节点到1节点的最短距离;
        ans+=SPFA();
        printf("%lld\n",ans);
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值