[POJ 1511]Invitation Cards[链式前向星][SPFA]

题目链接:[POJ 1511]Invitation Cards[链式前向星][SPFA]
题意分析:
每天从点1都会有 n1 个孩子需要到点 2 ~ n去做事。现在给出 a>b 的费用,问,每天从 2 ~ n这些点来回一趟最少需要多少钱?
解题思路:
考虑本题边的个数和点的个数均 <=1e6 <script type="math/tex" id="MathJax-Element-118"><= 1e6</script>。可以使用SPFA进行操作,使用链式前向星存储图。

这里处理来回距离有一个小技巧,spfa可以求得点1到所有点的最短距离;那么把整个图转置一下(所有边都取它的反向边建图),再求1到所有点的最短距离,此时的最短距离就是所有点到1的最短距离。

为什么要用链式前向星存储图呢?因为本题是一个稀疏图,使用邻接矩阵极限样例情况下占用空间至少为 1e6 ,而链式前向星最多 1e6 。其次,邻接矩阵的vector调用,需要申请空间,无形中又拖慢了速度。而链式前向星只需要调用已有数组。
个人感受:
一直不能理解链式前向星有什么好的,结果这题就教做人了。死活就是T,改用链式前向星就A了。可怕 山口山
具体代码如下:

#include<cstdio>
#include<iostream>
#include<queue>
#define ll long long
using namespace std;

const ll INF = 0x7f7f7f7f;
const int MAXN = 1e6 + 111;

struct Edge{
    int to, next;
    ll val;
}edge[2][MAXN];

ll dis[2][MAXN];
int head[2][MAXN], cnt;
bool in[MAXN];

void make_map(int from, int to, ll v, int sta)
{
    edge[sta][cnt].to = to;
    edge[sta][cnt].val = v;
    edge[sta][cnt].next = head[sta][from];
    head[sta][from] = cnt;
}

void spfa(int s, int sta)
{
    dis[sta][s] = 0;
    queue<int> q;
    q.push(s);
    in[s] = 1;
    while (q.size())
    {
        int cur = q.front(); q.pop(); in[cur] = 0;
        for (int i = head[sta][cur]; ~i; i = edge[sta][i].next)
        {
            Edge &e = edge[sta][i];
            if (dis[sta][e.to] > dis[sta][cur] + e.val)
            {
                dis[sta][e.to] = dis[sta][cur] + e.val;
                if (!in[e.to])
                {
                    in[e.to] = 1;
                    q.push(e.to);
                }
            }
        }
    }
}

int main()
{
    int kase, p, q, u, v, w; scanf("%d", &kase);
    while (kase --)
    {
        scanf("%d%d", &p, &q);
        for (int i = 1; i <= p; ++i)
        {
            dis[0][i] = dis[1][i] = INF;
            head[0][i] = head[1][i] = -1;
        }
        cnt = 0;
        while (q --)
        {
            scanf("%d%d%d", &u, &v, &w);
            make_map(u, v, w, 0);
            make_map(v, u, w, 1);
            ++cnt;
        }
        spfa(1, 0);
        spfa(1, 1);
        ll ans = 0;
        for (int i = 2; i <= p; ++i)
        {
            // cout << dis[0][i] << ' ' << dis[1][i] << '\n';
            ans += dis[0][i] + dis[1][i];
        }
        printf("%lld\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值