POJ 1511

Description

n-1个人从1号点出发,到剩余n-1个宣传点,然后再回到1号点汇报结果,求所有人往返路径和的最小值

Input
输入由T个案例组成。输入的第一行只包含正整数T。
接下来是N和M,1 <= N,M <= 1000000,表示N个点和连接N个点的M条边。
然后有M行,每行包括三个值U,V,W,表示从点U到点V需要W的路程。你可以假设该图连通。
注意是单向通道!!!

Output
对于每个案例,打印一行,表示路径总和的最小值。

Sample Input

2
2 2
1 2 13
2 1 33
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50

Sample Output

46
210

题目大意:

输入一个 t 表示 t 组数据,对于每组数据,输入n和m,表示有n个顶点和m条有向边,你需要输出所有人往返路径和的最小值。

解题思路:

链式前向星存图 + 反向建图 + spfa,题目中提到了往返一次,说明这道题建图时建正反两个,这里使用链式前向星存图,跑两次spfa最后取{min(dis[i] + dis1[i])} 即可,注意数据范围可能很大,开long lonng ,不开wa了一次。

Code:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define lowbit(x) x & (-x)

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 50;
const int M = 1e4 + 50;

int h[N], ne[N], e[N], idx;
int h1[N], ne1[N], e1[N], idx1;
ll w[N], w1[N];
ll dis[N], dis1[N];
bool vis[N];
int T, n, m;

void add(int a, int b, ll c)//正向反向各建一个图
{
	e[idx] = b;
	w[idx] = c;
	ne[idx] = h[a];
	h[a] = idx++;

	e1[idx1] = a;
	w1[idx1] = c;
	ne1[idx1] = h1[b];
	h1[b] = idx1++;
}

void init()//多组数据不要忘记初始化
{
	idx = idx1 = 0;
	memset(h, -1, sizeof h);
	memset(h1, -1, sizeof h1);
}

void spfa(int s)
{
	memset(dis, 0x3f, sizeof dis);
	dis[s] = 0;

	queue<int > q;
	q.push(s);

	memset(vis, false, sizeof vis);
	vis[s] = true;

	while (!q.empty())
	{
		int t = q.front();
		q.pop();

		vis[t] = false;

		for (int i = h[t]; ~i; i = ne[i])
		{
			int j = e[i];
			if (dis[t] + w[i] < dis[j])
			{
				dis[j] = dis[t] + w[i];
				if (!vis[j])
				{
					q.push(j);
					vis[j] = true;
				}
			}
		}
	}
}

void respfa(int s)
{
	memset(dis1, 0x3f, sizeof dis1);
	dis1[s] = 0;

	queue<int > q;
	q.push(s);

	memset(vis, false, sizeof vis);
	vis[s] = true;

	while (!q.empty())
	{
		int t = q.front();
		q.pop();

		vis[t] = false;

		for (int i = h1[t]; ~i; i = ne1[i])
		{
			int j = e1[i];
			if (dis1[t] + w1[i] < dis1[j])
			{
				dis1[j] = dis1[t] + w1[i];
				if (!vis[j])
				{
					q.push(j);
					vis[j] = true;
				}
			}
		}
	}
}

int main()
{
	scanf("%d", &T);
	
	while (T --)
	{
		init();

		scanf("%d%d", &n, &m);

		while (m --)
		{
			int a, b;
			ll c;
			scanf("%d%d%lld", &a, &b, &c);
			add(a, b, c);
		}

		spfa(1);//建好图之后跑两遍spfa即可
		respfa(1);

		ll ans = 0;//最后答案会爆int
		for (int i = 1; i <= n; i++) ans += dis[i] + dis1[i];

		printf("%lld
", ans);
	}

	return 0;
}
原文地址:https://www.cnblogs.com/Hayasaka/p/14294124.html