1. 程式人生 > >POJ 1511 Invitation Cards(SPFA)

POJ 1511 Invitation Cards(SPFA)

圖論題目還是做得少,這麼簡單的SPFA都不會做。。看了大神的部落格 http://www.cnblogs.com/scau20110726/archive/2013/05/04/3060299.html

下面是人家的解釋:

最短路

題意: 強調是有向圖 , n個點(1到n標號)m條邊,求出點1到所有點的最短路之和 + 所有點到點1的最短路之和

什麼?求一次最短路,然後 x 2 就是答案? 這樣是錯的,如果是無向圖的話可以這樣,因為可以逆回去走。但是有向圖顯然不是,點1到點a的最短路,和點a到點1的最短路是完全不同的,值不同走過的路徑也不同.要求點1到所有點的最短路,直接執行一次最短路即可。但是要求所有點到點1的最短路,難道要對所有點執行一次最短路嗎?一看點數就可以否定這個想法。可以這樣想,如果點a到點1存在最短路,那麼把這條路徑的邊全部取反,就是點1到點a的最短路了。所有在求了第1次最短路後,將 整個圖的邊取反,再求一次點1到所有點的最短路就行了,可以知道邊都取反後,第一次走過的路徑都不會再走到(都取反了),而從點a可能到點1的可能的邊都成了點1到點a的可能的邊。

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

using namespace std;

const int MAX_N = 1000000 + 100;
const int INF = 0x3f3f3f3f;

int head[MAX_N];
long long dis[MAX_N];
bool vis[MAX_N];

struct Edge
{
    int v, next;
    long long w;
};

struct E
{
    int u, v;
    long long w;
};

E e[MAX_N];
Edge edge[MAX_N];
int cnt, p, q;

void addEdge(int u, int v, long long w)
{
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

long long SPFA(int src)
{
    int u;
    memset(vis, 0, sizeof(vis));
    memset(dis, INF, sizeof(dis));
    dis[src] = 0;
    vis[src] = true;
    queue <int> Q;
    Q.push(src);
    while(!Q.empty())
    {
        u = Q.front();
        Q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            if(dis[edge[i].v] > dis[u] + edge[i].w)
            {
                dis[edge[i].v] = dis[u] + edge[i].w;
                if(!vis[edge[i].v])
                {
                    Q.push(edge[i].v);
                    vis[edge[i].v]= true;
                }
            }
        }
    }
    long long sum = 0;
    for(int i = 1; i <= p; i++)
        sum += dis[i];
    return sum;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        init();
        int u, v;
        long long w;
        scanf("%d%d", &p, &q);
        for(int i = 0; i < q; i++)
        {
            scanf("%d%d%lld", &u, &v, &w);
            addEdge(u, v, w);
            e[i].u = u, e[i].v = v, e[i].w = w;
        }
        long long sum = SPFA(1);
        init();
        for(int i = 0; i < q; i++)
            addEdge(e[i].v, e[i].u, e[i].w);
        sum += SPFA(1);
        printf("%lld\n", sum);
    }
    return 0;
}