poj 1511 Invitation Cards

最短路

题意:  强调是有向图 , n个点(1到n标号)m条边,求出点1到所有点的最短路之和 + 所有点到点1的最短路之和

什么?求一次最短路,然后 x 2 就是答案? 这样是错的,如果是无向图的话可以这样,因为可以逆回去走。但是有向图显然不是,点1到点a的最短路,和点a到点1的最短路是完全不同的,值不同走过的路径也不同.要求点1到所有点的最短路,直接运行一次最短路即可。但是要求所有点到点1的最短路,难道要对所有点运行一次最短路吗?一看点数就可以否定这个想法。可以这样想,如果点a到点1存在最短路,那么把这条路径的边全部取反,就是点1到点a的最短路了。所有在求了第1次最短路后,将 整个图的边取反,再求一次点1到所有点的最短路就行了,可以知道边都取反后,第一次走过的路径都不会再走到(都取反了),而从点a可能到点1的可能的边都成了点1到点a的可能的边

 

代码用了spfa算法,用queue和stack来辅助对时间的影响不大,但是stack稍快一点(只从上次后我发现其实stack都比queue快,一般情况下,更不用题特殊情况了)

另外用dij+heap也行,朴素的dij应该是超时的,虽然没写

 

#include <cstdio>

#include <cstring>

#include <queue>

#include <stack>

using namespace std;

#define N 1000010

#define INF 0x3f3f3f3f



typedef long long ll;

ll d[N];

int n,tot;

int head[N];

bool ins[N];

struct edge

{

    int u,v,w,next;

}e[N],tt[N];



void add(int u ,int v ,int w , int k)

{

    e[k].u = u;

    e[k].v = v;

    e[k].w = w;

    e[k].next = head[u];

    head[u] = k;

}



ll spfa_stack()

{

    stack<int>sta;

    memset(d,0x3f,sizeof(d));

    memset(ins,false,sizeof(ins));

    while(!sta.empty()) sta.pop();

    d[1] = 0;

    ins[1] = true;

    sta.push(1);

    while(!sta.empty())

    {

        int u = sta.top();

        sta.pop();

        ins[u] = false;

        for(int k=head[u]; k!=-1; k=e[k].next)

        {

            int v =e[k].v;

            int w = e[k].w;

            if( d[u] + w < d[v] )

            {

                d[v] = d[u] + w;

                if(!ins[v])

                {

                    ins[v] = true;

                    sta.push(v);

                }

            }

        }

    }

    ll res = 0;

    for(int i=1; i<=n ; i++)

        res += d[i];

    return res;

}



int main()

{

    int T;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%d%d",&n,&tot);



        memset(head,-1,sizeof(head));

        for(int i=0; i<tot; i++)

        {

            int u,v,w;

            scanf("%d%d%d",&u,&v,&w);

            tt[i].u = u; tt[i].v = v; tt[i].w = w;

            add(u,v,w,i);

        }

        ll suma = spfa_stack();



        memset(head,-1,sizeof(head));

        for(int i=0; i<tot; i++)

            add(tt[i].v , tt[i].u , tt[i].w , i);

        ll sumb = spfa_stack();



        printf("%lld\n",suma+sumb);

    }

    return 0;

}

 

你可能感兴趣的:(poj)