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;
}

 

posted @ 2013-05-04 22:38  Titanium  阅读(1120)  评论(0编辑  收藏  举报