POJ 1511 Invitation Cards(正反图两次SPFA&邻接表)

题目链接: kuangbin带你飞 专题四 最短路练习 J - Invitation Cards

题意

求源点到各点的往返最短路之和

思路

本体思路没什么难度,分别用正反图求两次单源最短路即可,邻接表不好逆置,直接在最初构建两个图即可。
数据量相当大,timeout了两次,第一次是直接spfa,第二次用vector做邻接表仍然超时,第三次自己构建邻接表算是过了

代码

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<queue>

using namespace std;

const int N = 1000009;
const int MAX = 0x3f3f3f3f;

bool vis[N];
long long d[N];
long long ans[N] = {};
int head1[N], head2[N];
struct Edge
{
    int u, v, w, next;
}e1[N], e2[N];

void spfa(int n, Edge e[], int head[])
{
    memset(vis, 0, sizeof(vis));
    for(int i=1; i<=n; i++)
        d[i] = MAX;
    d[1] = 0;
    vis[1] = 1;
    queue<int> q;
    q.push(1);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for(int i=head[x]; i!=-1; i=e[i].next)
        {
            if(d[e[i].v] > d[x] + e[i].w)
            {
                d[e[i].v] = d[x] + e[i].w;
                if(!vis[e[i].v])
                {
                    q.push(e[i].v);
                    vis[e[i].v] = 1;
                }
            }
        }
    }
    for(int i=1; i<=n; i++)
        ans[i] += d[i];
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        memset(ans, 0, sizeof(ans));
        memset(head1, -1, sizeof(head1));
        memset(head2, -1, sizeof(head2));
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d", &e1[i].u, &e1[i].v, &e1[i].w);
            e1[i].next = head1[e1[i].u];
            head1[e1[i].u] = i;
            e2[i].u = e1[i].v;
            e2[i].v = e1[i].u;
            e2[i].w = e1[i].w;
            e2[i].next = head2[e2[i].u];
            head2[e2[i].u] = i;
        }
        spfa(n, e1, head1);
        spfa(n, e2, head2);
        long long rel = 0;
        for(int i=1; i<=n; i++)
            rel += ans[i];
        printf("%lld\n", rel);
    }
    return 0;
}