HDU 1535 Invitation Cards

版权声明:本人QQ 249712949 欢迎交流算法(请备注)。 https://blog.csdn.net/coord_/article/details/88903494

传送门

最短路。
这题瞎扯一大堆废话,其实就是一个有向图,先求从1到其他点的最短路,再求从其他点到1的最短路,上述2(n-1)个最短路的值的和作为答案(题目保证是强连通图)。

从其他点到1的最短路,我们不可能把其他每个点都作为起点运行一下,肯定会超时的。这就要用到反向建图。在正向图中某个点到1的最短路就相当于在反向图中1到这个点的最短路。(反向建图指的是把边的指向反转,和边权无关,想一想什么时候用到了边权反转?)所以只用来两次最短路算法就行了。

这道题我当时还用了链式前向星来存图,可以参考这个
这种结构把最晚输入的边在边集中的序号作为这条边起点的head[]值,然后以边集序号为索引,用next[]连接一个又一个,就像在边集中从后往前跳跃,对应的边都是同一起点的。要注意next[]数组的索引和边表的索引是一致的。
感觉这种结构比我之前写的邻接表要省空间。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <utility>
#include <queue>
using namespace std;

const int INF = 1e9;
const int MAX = 1e6 + 2;
int N, P, Q;
bool inq[MAX];
int d[MAX];
int ans;

//vector<pair<int, int>> v[2][MAXP];

struct Edge
{
	int n1, n2, w;
};
vector<Edge> ve;
int first[MAX], nxt[MAX];

void init()
{
	memset(first, -1, sizeof first);
	memset(nxt, -1, sizeof nxt);
	ans = 0;
	ve.clear();
}

void spfa(int id)     // 这个id是指明spfa算法用边集中的n1还是n2作为当前点的后驱
{
	fill(d + 1, d + P + 1, INF);
	memset(inq, 0, sizeof inq);
	queue<int> q;
	d[1] = 0;
	inq[1] = true;
	q.push(1);

	for (; !q.empty();)
	{
		int t = q.front();
		q.pop();
		inq[t] = false;
		for (int i = first[t]; i != -1; i = nxt[i])
		{
			int u;
			if (!id) u = ve[i].n2;                  //
			else u = ve[i].n1;
			int w = ve[i].w;

			if (d[t] + w < d[u])
			{
				d[u] = d[t] + w;
				if (!inq[u])
				{
					q.push(u);
					inq[u] = true;
				}
			}
		}
	}
}

void reverse()
{
	memset(first, -1, sizeof first);
	memset(nxt, -1, sizeof nxt);
	for (int i = 0; i < ve.size(); i++)
	{
		nxt[i] = first[ve[i].n2];
		first[ve[i].n2] = i;
	}
}

int main()
{
	int a, b, c;
	scanf("%d", &N);
	for (; N--;)
	{
		scanf("%d%d", &P, &Q);
		init();
		for (; Q--;)
		{
			scanf("%d%d%d", &a, &b, &c);
			ve.push_back(Edge{ a, b, c });

			int index = ve.size() - 1;
			nxt[index] = first[a];                  // 链式前向星存图
			first[a] = index;
		}
		spfa(0);
		for (int i = 2; i <= P; i++) ans += d[i];
		reverse();
		spfa(1);
		for (int i = 2; i <= P; i++) ans += d[i];
		printf("%d\n", ans);
	}

    return 0;
}

猜你喜欢

转载自blog.csdn.net/coord_/article/details/88903494