POJ - 3159 Candies 【向前星+dij】

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

差分约束问题,下面把要注意的地方讲下。

首先这道题是卡队列的,如果你用的是spfa,要把queue换成stack才能过,至于为什么就不是很清楚了(可能是因为题目的数据是稠密图,每次队列的插入和删除开销大,和下面要用向前星一样,vector比较适合用来存储稀疏图的边,而稠密图最好用向前星),要么就是dij的堆优化。

如果你用的是dij的堆优化的话要用向前星存边才能稳A,如果你用的是vector,网上有看到能到A的代码,但是我写的A不了。

下面简单讲讲向前星的存边过程。

首先是一个head数组,用来记录同起点的边的首个边的编号,edge 用来存储边的数据,最初设置所有的head都是-1。

假设有3条边 分别是 (1, 2), (1, 3) ,(1, 4),他们的起点都是相同的,给他们依次编号为1,2,3,我们从左到右依次操作。

head[1] -> -1

head[1]  -> edge[1] -> -1

head[1] -> edge[2] -> edge[1] -> -1

head[1] -> edge[3 -> edge[2] -> edge[1] -> -1

过程是不是很像链表的插入,每次把新加的边插在 head[1] 和下一个边的中间。每一个边都需要一个next变量来指向下一个相邻的边的编号。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <queue>
#include <string>

using namespace std;

const int Maxn = 2e5+10;
const int INF = 0x3f3f3f3f;

struct Edge {
	int v, w, next;
	Edge(int x = 0, int y = 0): v(x), w(y){
	}
	bool operator < (const Edge &a1) const {
		return w > a1.w;
	}
} edge[Maxn];

int d[30010], edge_cnt = 0, head[30010];
vector<int> G[30010];
bool vis[30010];

void add(int from, int to, int w) {
    edge[edge_cnt].v = to;
    edge[edge_cnt].w = w;
    edge[edge_cnt].next = head[from];
    head[from] = edge_cnt++;
}

void spfa(int N) {
	memset(vis, false, sizeof(vis));
	d[1] = 0;
	priority_queue<Edge> qu;
	qu.push(Edge(1, 0));

	while (!qu.empty()) {
		int v = qu.top().v; qu.pop();
		if(vis[v]) continue;
		vis[v] = true;

		for(int i = head[v]; i != -1; i = edge[i].next) {
			Edge &e = edge[i];
			if(d[e.v] > d[v]+e.w) {
				d[e.v] = d[v]+e.w;
				qu.push(Edge(e.v, d[e.v]));
			}
		}
	}
}

int main (void)
{
	int N, M;
	scanf("%d%d", &N, &M);
		int n = 0, u, v, w;
		memset(head, -1, sizeof(head));
		for(int i = 0; i < M; ++i) {
			scanf("%d%d%d", &u, &v, &w);
			add(u, v, w);
		}
		for(int i = 1; i <= N; ++i) d[i] = INF;
		spfa(N);
		printf("%d\n", d[N]);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值