POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA)

POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA)

ACM

题目地址:POJ 3013

题意:

圣诞树是由n个节点和e个边构成的,点编号1-n,树根为编号1,选择一些边,使得所有节点构成一棵树,选择边的代价是(子孙的点的重量)×(这条边的价值)。求代价最小多少。

分析:

单看每个点被计算过的代价,很明显就是从根到节点的边的价值。所以这是个简单的单源最短路问题。

不过坑点还是很多的。

点的数量高达5w个,用矩阵存不行,只能用边存。

还有路径和结果会超int,所以要提高INF的上限,(1<<16)*50000即可。

可以用Dijkstra+优先队列做,也可以用SPFA做,貌似SPFA会更快。我这里用的是Dijkstra,要1s多...回头要用SPFA做一遍。

用SPFA做了一遍发现也是1s多,看了是STL用多了 = =。

嘛,留个模板。

代码:

(Dijkstra+priority_queue)

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        3013.cpp
*  Create Date: 2014-07-27 09:54:35
*  Descripton:  dijkstra
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
#include <queue>
#define repf(i,a,b) for(int i=(a);i<=(b);i++)

const int N = 50100;
const long long INF = (long long)(1<<16)*N;

struct Edge {
	int from, to;
	int dist;
};

struct HeapNode {
	int d;
	int u;
	bool operator < (const HeapNode rhs) const {
		return d > rhs.d;
	}
};

struct Dijkstra {
	int n, m;			// number of nodes and edges
	vector<Edge> edges;
	vector<int> G[N];	// graph
	bool vis[N];	// visited?
	long long d[N];		// dis
	int p[N];		// prevent edge

	void init(int _n) {
		n = _n;
	}

	void relief() {
		for (int i = 0; i < n; i++) {
			G[i].clear();
		}
		edges.clear();
	}

	void AddEdge(int from, int to, int dist) {
		// if non-directed, add twice
		edges.push_back((Edge){from, to, dist});
		m = edges.size();
		G[from].push_back(m - 1);
	}

	void dijkstra(int s) {
		priority_queue<HeapNode> Q;
		for (int i = 0; i < n; i++) {
			d[i] = INF;
			vis[i] = 0;
		}
		d[s] = 0;

		Q.push((HeapNode){0, s});
		while (!Q.empty()) {
			HeapNode x = Q.top();
			Q.pop();
			int u = x.u;
			if (vis[u]) {
				continue;
			}
			vis[u] = true;
			for (int i = 0; i < G[u].size(); i++) {	// update the u's linking nodes
				Edge& e = edges[G[u][i]];	//ref for convenient
				if (d[e.to] > d[u] + e.dist) {
					d[e.to] = d[u] + e.dist;
					p[e.to] = G[u][i];
					Q.push((HeapNode){d[e.to], e.to});
				}
			}
		}
	}
};

int t;
int e, v, x, y, d, w[N];

int main() {
	scanf("%d", &t);
	Dijkstra di;

	while (t--) {
		scanf("%d%d", &v, &e);
		di.init(v);

		repf (i, 0, v - 1) {
			scanf("%d" ,&w[i]);
		}
		repf (i, 0, e - 1) {
			scanf("%d%d%d", &x, &y, &d);
			di.AddEdge(x - 1, y - 1, d);
			di.AddEdge(y - 1, x - 1, d);
		}
		di.dijkstra(0);

		long long ans = 0;
		bool ring = false;
		repf (i, 0, v - 1) {
			if (di.d[i] == INF) {
				ring = true;
			}
			ans += w[i] * di.d[i];
		}
		if (ring) {
			cout << "No Answer" << endl;
		} else {
			cout << ans << endl;
		}

		if (t)	// if not the last case
			di.relief();
	}
	return 0;
}

(SPFA)

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        3013_spfa.cpp
*  Create Date: 2014-07-27 15:44:45
*  Descripton:  spfa
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
#include <queue>
#define repf(i,a,b) for(int i=(a);i<=(b);i++)

const int N = 50100;
const long long INF = (long long)(1<<16)*N;

struct Edge {
	int from, to;
	int spst;
};

struct SPFA {
	int n, m;
	vector<Edge> edges;
	vector<int> G[N];	// the edges which from i
	bool vis[N];
	long long d[N];	// sps
	int p[N];		// prevent

	void init(int _n) {
		n = _n;
	}

	void relief() {
		for (int i = 0; i < n; i++)
			G[i].clear();
		edges.clear();
	}

	void AddEdge(int from, int to, int spst) {
		// if non-sprected, add twice
		edges.push_back((Edge){from, to, spst});
		m = edges.size();
		G[from].push_back(m - 1);
	}

	void spfa(int s) {
		queue<int> Q;
		while (!Q.empty())
			Q.pop();
		for (int i = 0; i < n; i++) {
			d[i] = INF;
			vis[i] = 0;
		}
		d[s] = 0;
		vis[s] = 1;
		Q.push(s);
		while (!Q.empty()) {
			int u = Q.front();
			Q.pop();
			vis[u] = 0;
			for (int i = 0; i < G[u].size(); i++) {
				Edge& e = edges[G[u][i]];
				if (d[e.to] > d[u] + e.spst) {
					d[e.to] = d[u] + e.spst;
					p[e.to] = G[u][i];
					if (!vis[e.to]) {
						vis[e.to] = 1;
						Q.push(e.to);
					}
				}
			}
		}

	}
};

int t;
int e, v, x, y, d, w[N];

int main() {
	scanf("%d", &t);
	SPFA sp;

	while (t--) {
		scanf("%d%d", &v, &e);
		sp.init(v);

		repf (i, 0, v - 1) {
			scanf("%d" ,&w[i]);
		}
		repf (i, 0, e - 1) {
			scanf("%d%d%d", &x, &y, &d);
			sp.AddEdge(x - 1, y - 1, d);
			sp.AddEdge(y - 1, x - 1, d);
		}
		sp.spfa(0);

		long long ans = 0;
		bool ring = false;
		repf (i, 0, v - 1) {
			if (sp.d[i] == INF) {
				ring = true;
			}
			ans += w[i] * sp.d[i];
		}
		if (ring) {
			cout << "No Answer" << endl;
		} else {
			cout << ans << endl;
		}

		if (t)	// if not the last case
			sp.relief();
	}
	return 0;
}

POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA),布布扣,bubuko.com

时间: 2024-10-12 23:58:12

POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA)的相关文章

POJ 3013 Big Christmas Tree(最短Dijkstra+优先级队列优化,SPFA)

POJ 3013 Big Christmas Tree(最短路Dijkstra+优先队列优化,SPFA) ACM 题目地址:POJ 3013 题意: 圣诞树是由n个节点和e个边构成的,点编号1-n.树根为编号1,选择一些边.使得全部节点构成一棵树.选择边的代价是(子孙的点的重量)×(这条边的价值). 求代价最小多少. 分析: 单看每一个点被计算过的代价,非常明显就是从根到节点的边的价值.所以这是个简单的单源最短路问题. 只是坑点还是非常多的. 点的数量高达5w个,用矩阵存不行.仅仅能用边存. 还

poj 3013 Big Christmas Tree (dij+优先队列优化 求最短路)

模板 题意:给你一个图,1总是为根,每个边有单位价值,每个点有权重. 每条边的价值 = sum(后继节点权重)*边的单位价值. 求树的最小价值,即构成一棵树的n-1条边的最小价值. 算法: 1.因为每个边的价值都要乘以后来访问的节点的权重,而走到后来访问的点必经过这条边. 实际上总价值就是  到每个点的最短路径*这个点的权重. 2.但是这个题 数据量真的太大了,50000个点,50000条边. 写普通的dij算法tle. 必须加优先队列优化- - 据说spfa也能过,但是spfa算法不稳定- -

POJ 3013 Big Christmas Tree【最短路变形,DIjkstra堆优化+spfa算法】

Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23064   Accepted: 4987 Description Christmas is coming to KCM city. Suby the loyal civilian in KCM city is preparing a big neat Christmas tree. The simple structure of t

poj 3013 Big Christmas Tree

Big Christmas Tree 题意:输入v个节点和e条边(0 ≤ v, e ≤ 50000) 的图,第二行输入每个节点的权值,之后e行输入每条边的端点和权值: 问是否能找出一棵树,使得树中的边权乘以该边下面的子孙节点权值之和的sigma总和最小:(树以1为根节点) Sample Input 1 200 10 20 30 40 50 60 1 2 1 2 3 3 2 4 2 3 5 4 3 7 2 3 6 3 1 5 9 (删掉) Sample Output 1210 分析:如果计算最小乘

poj 3013 Big Christmas Tree (dij+优先级队列优化 求最短)

模板 意甲冠军:给你一个图,1始终根,每一方都有单价值,每个点都有权重新. 每个边缘的价格值 = sum(后继结点重)*单价方值. 最低价格要求树值,它构成了一棵树n-1条边的最小价值. 算法: 1.由于每一个边的价值都要乘以后来訪问的节点的权重.而走到后来訪问的点必经过这条边. 实际上总价值就是  到每一个点的最短路径*这个点的权重. 2.可是这个题 数据量真的太大了.50000个点,50000条边. 写普通的dij算法tle. 必须加优先队列优化- - 据说spfa也能过.可是spfa算法不

SPFA/Dijkstra POJ 3013 Big Christmas Tree

题目传送门 题意:找一棵树使得造价最少,造价为每个点的子节点造价和*边的造价和 分析:最短路跑出1根节点到每个点的最短边权值,然后每个点的权值*最短边距和就是答案,注意INF开足够大,n<=1特判.Dijkstra 和 SPFA都行 代码: #include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <vector> #includ

最短路--dijkstra+优先队列优化模板

不写普通模板了,还是需要优先队列优化的昂 1 #include<stdio.h> //基本需要的头文件 2 #include<string.h> 3 #include<queue> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 typedef pair<int,int> pii; 8 const int INF=0x3f3f3f3f; 9 10 11

poj 3031 Big Christmas Tree(水spfa)

http://poj.org/problem?id=3013 题意: Because of a technical difficulty, price of an edge will be (sum of weights of all descendant nodes) × (unit price of the edge).这句话一直没看懂.后面还以为是最小生成树. 正确题意是:给一个无向图,计算每个点到1节点的最短路径(dis[i]) * 每个节点的weights之和. 注意:边权值等要用__

POJ 2387-Til the Cows Come Home(最短路Dijkstra+优先队列)

Til the Cows Come Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30007   Accepted: 10092 Description Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the