POJ1511Invitation Cards(国产算法SPFA)

题目链接:http://poj.org/problem?id=1511


题目大意:给出n个点和n条有向边,求所有点到源点1的来回最短路之和(保证每个点都可以往返源点1)

解题思路:这个数据范围太大,明显的不能用floyd,dijstra,bellman-ford这些算法,用spfa的话也不能用邻接矩阵存,因为点太多了,所以采用spfa的邻接表存储搞定

稍微有点注意的地方是,来回之和只需要将所有的边反向再从1到所有点求最短路就是他们的最短回路,而且这个题

由于数据很大,所以最大值 inf 要设置很大。



#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
#define maxn 1000010
#define inf 0xFFFFFFFF
int n, m;
int head[2][maxn], vis[maxn];
long long sum, dis[maxn];  //数据要大点
struct node
{
    int to, w, next;
}edge[2][maxn];
//国产算法核心代码,queue 实现
void SPFA(int a) 
{
    int v, i, b;
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n; i++)
        dis[i] = inf;
    queue<int>q;
    q.push(1);
    vis[1] = 1;
    dis[1] = 0;
    while(!q.empty())
    {
        v = q.front();
        q.pop();
        vis[v] = 0;
        for(i = head[a][v]; i != -1; i = edge[a][i].next)
        {
            b = edge[a][i].to;
            if(dis[b] > dis[v]+edge[a][i].w)
            {
                dis[b] = dis[v]+edge[a][i].w;
                if(!vis[b])
                {
                    vis[b] = 1;
                    q.push(b);
                }
            }
        }
    }
}
int main()
{
    int Case, a, b, w, i;
    cin>>Case;
    while(Case--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
        {
            head[0][i] = -1;
            head[1][i] = -1;
        }
        // 用静态邻接表( 又称为链式前向星 )存储,效率很高。
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &a, &b, &w);
            edge[0][i].to = b;
            edge[0][i].w = w;
            edge[0][i].next = head[0][a];
            head[0][a] = i;
            // 构造反图
            edge[1][i].to = a;
            edge[1][i].w = w;
            edge[1][i].next = head[1][b];
            head[1][b] = i;
        }
        sum = 0;
        SPFA(0);
        for(int i = 1; i <= n; i++)
            sum += dis[i];
        SPFA(1);
        for(int i = 1; i <= n; i++)
            sum += dis[i];
        printf("%I64d\n", sum);
    }
    return 0;
}



转载自 http://blog.csdn.net/wangjian8006/article/details/7871158


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值