Invitation Cards(SPFA + 反向建边)

传送门

  • 很经典的反向建边题目,AC代码使用SPFA做的,但是刚开始用的是朴素版的dijkstra,一直RE...

分析

  1. n个站点每个站点都要去一个人,求来回的总花销,那么可以确定的是第一个人不需要花钱,因为要从1号站台出发,所以第一个人不用动
  2. 路是单向的路,也就是有向图,从A到B和从B到A的花费很可能是不一样的
  3. 对于除第一个人之外的其他人,先到他的目标点,然后再从目标点回来,计算最短花费
  4. 因此,先正向跑一边最短路,再反向跑一遍最短路,最后计算总和就OK了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
using namespace std;
typedef long long ll;
const int N = 1000010;
bool vis[N];
struct Edge{
	int v, w, next;
}edge[N], edge1[N];
int tot, head[N], head1[N];
ll dist[N], sum1[N], sum2[N], p, q;
void add(int u, int v, int w){
	edge[tot].next = head[u];
	edge[tot].v = v;
	edge[tot].w = w;
	head[u] = tot;
	edge1[tot].next = head1[v];
	edge1[tot].v = u;
	edge1[tot].w = w;
	head1[v] = tot ++;
}
void spfa1(){
	queue<int> q;
	memset(dist, 0x3f3f3f3f, sizeof dist);
	memset(vis, 0, sizeof vis);
	dist[1] = 0;
	q.push(1);
	vis[1] = 1;
	while(q.size()){
		int t = q.front();
		q.pop();
		vis[t] = false;
		for(int i = head[t]; i != -1; i = edge[i].next){
			int to = edge[i].v;
			int w = edge[i].w;
			if(dist[to] > dist[t] + w){
				dist[to] = dist[t] + w;
				vis[t] = true;
				q.push(to);
			}
		}
	}	
}
void spfa2(){
	queue<int> q;
	memset(dist, 0x3f3f3f3f, sizeof dist);
	memset(vis, 0, sizeof vis);
	dist[1] = 0;
	q.push(1);
	vis[1] = 1;
	while(q.size()){
		int t = q.front();
		q.pop();
		vis[t] = false;
		for(int i = head1[t]; i != -1; i = edge1[i].next){
			int to = edge1[i].v;
			int w = edge1[i].w;
			if(dist[to] > dist[t] + w){
				dist[to] = dist[t] + w;
				vis[t] = true;
				q.push(to);
			}
		}
	}	
}
int main(){
	int t;
	cin >> t;
	while(t --){
		memset(head, -1, sizeof head);
		memset(head1, -1, sizeof head1);
		memset(sum1, 0, sizeof sum1);
		memset(sum2, 0, sizeof sum2);
		scanf("%lld%lld", &p, &q);
		while(q --){
			ll a, b, p;
			scanf("%lld%lld%lld", &a, &b, &p);
			add(a, b, p);
		}
		spfa1();
		for(int i = 1; i <= p; i ++)
			sum1[i] = dist[i];
		spfa2();
		for(int i = 1; i <= p; i ++)
			sum2[i] = dist[i];
		ll res = 0;
		for(int i = 2; i <= p; i ++)
			res += sum1[i] + sum2[i];
		printf("%lld
", res);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/pureayu/p/14440420.html