题解 UVA721 【Invitation Cards】

题意简述:

求 1 号点到其他点的最短路和其他点到 1 号点的最短路。

思路:

第一眼想到 floyd 但是一看 (1le P,Q le 1e6) 直接暴毙。

再仔细观察题目,发现只需要求1到其他点的最短路其他点到1的最短路

你品,你细品。

举个栗子:样例第二组数据:

4.29tj1.png

如果我们把这个图反过来建//add(y,x,z)

就成了这个模样:

4.29tj2.png

我们惊奇的发现,倒过来建图之后,1 到其他点的最短路就是原来图的其他点到 1 的最短路!

Nice!让我们开始写代码。

代码

几点说明:

  1. 最短路为标准 Dijkstra ,spfa已死,Dijkstra当道!(其实这个题应该不卡 spfa )。
  2. 我采用链式前向星的方式建图,因为要建反图,前缀为 0 的是原图,为 1 的是反图。
#include<bits/stdc++.h>
#define F first
#define S second
using namespace std;
int n,m,nxt[2][1000006],cost[2][1000006],to[2][1000006],h[2][1000006],cnt1,cnt2;
void add(int x,int y,int z) {
	to[0][++cnt1]=y;
	to[1][++cnt2]=x;
	nxt[0][cnt1]=h[0][x];
	nxt[1][cnt2]=h[1][y];
	cost[0][cnt1]=z;
	cost[1][cnt2]=z;
	h[0][x]=cnt1;
	h[1][y]=cnt2;
}
priority_queue< pair<int,int> >q;
int dis[1000006];
bool vis[1000006];
int dijk(int opt) {
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	while(q.size()) q.pop();
	dis[1]=0;
	q.push(make_pair(0,1));
	while(q.size()) {
		int u=q.top().S;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=h[opt][u];i;i=nxt[opt][i]) {
			int v=to[opt][i];
			if(dis[v]>dis[u]+cost[opt][i]) {
				dis[v]=dis[u]+cost[opt][i];
				q.push(make_pair(-dis[v],v));
			}
		}
	}
	int sum=0;
	for(int i=1;i<=n;i++)
		sum+=dis[i];
	return sum;
}
int main() {
	int t;
	cin>>t;
	while(t--) {
		memset(nxt,0,sizeof(nxt));
		memset(to,0,sizeof(to));
		memset(h,0,sizeof(h));
		memset(cost,0,sizeof(cost));
		cnt1=cnt2=0;
		cin>>n>>m;
		for(int i=1;i<=m;i++) {
			int x,y,z;
			cin>>x>>y>>z;
			add(x,y,z);
		}
		int ans1=dijk(0),ans2=dijk(1);
		cout<<ans1+ans2<<endl;
	}
    return 0;
}

其他

双倍经验放送:SP50

原文地址:https://www.cnblogs.com/ahawzlc/p/12837273.html