poj 1511 Invitation Cards

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

题意很简单,就是求1~N点的最短距离之和加上N~1点的最短距离之和。

注意的是顶点V和边数E都<=1000000故不能用邻接矩阵来做。

用邻接链表可能会tle(malloc函数可是很慢的)。因此用邻接表的另一种实现方式---数组来存图。

最后的结果可能会超出int 32的范围,要用long long来保存结果。

思路:建两张图,第一张为输入的图,第二张反向建图。

最后用spfa计算最短路径。

具体实现如下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Max_N 1000020
#define INF 0x3f3f3f3f
typedef long long ll;
typedef struct _node{
	int to, cost;
}edge;
edge G1[Max_N], G2[Max_N];
int V, E, sz1, sz2, Queue[Max_N << 2], vis[Max_N], dist[Max_N], node1[Max_N], node2[Max_N], next1[Max_N], next2[Max_N];
void built(int s, int to, int cost){
	G1[sz1] = (edge){ to, cost };
	next1[sz1] = node1[s];
	node1[s] = sz1++;
	G2[sz2] = (edge){ s, cost };
	next2[sz2] = node2[to];
	node2[to] = sz2++;
}
void spfa(int s, edge *G, int *node, int *next){
	int u, front = 0, rear = 0;
	for (u = 1; u <= V; u++) dist[u] = (u == s ? 0 : INF);
	Queue[rear++] = s;
	memset(vis, 0, sizeof(vis));
	while (front < rear){
		int v = Queue[front++];
		vis[v] = 0;
		for (u = node[v]; u != -1; u = next[u]){
			if (dist[G[u].to] > dist[v] + G[u].cost){
				dist[G[u].to] = dist[v] + G[u].cost;
				if (!vis[G[u].to]){
					vis[G[u].to] = 1;
					Queue[rear++] = G[u].to;
				}
			}
		}
	}
}
int main(){
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w+", stdout);
#endif
	int i, k, t;
	scanf("%d", &t);
	while (t--){
		sz1 = 0, sz2 = 0;
		scanf("%d %d", &V, &E);
		memset(node1, -1, sizeof(node1));
		memset(node2, -1, sizeof(node2));
		k = E;
		while (k--){
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			built(a, b, c);
		}
		ll res = 0;
		spfa(1, G1, node1, next1);
		for (i = 1; i <= V; i++) res += dist[i];
		spfa(1, G2, node2, next2);
		for (i = V; i > 0; i--) res += dist[i];
		printf("%lld\n", res);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值