P1342 请柬【题解】

最短路裸题

题目大意:

拿到题目扫了一眼,大概出了个这样的思路:建个图,先以 1 1 1为源点跑一次最短路,再以除了 1 1 1以外的 n − 1 n-1 n−1个点为源点跑 n − 1 n-1 n−1次最短路。若不考虑某已死的算法(我们采用 d i j k s t r a dijkstra dijkstra),这种做法的时间复杂度为 Θ ( N 2 log ⁡ N ) \Theta(N^2\log{N}) Θ(N2logN), q w q qwq qwq结果被 T \red{T} T上天了。后来又想到一个奇妙的性质:第二遍的 n − 1 n-1 n−1次 d i j k s t r a dijkstra dijkstra其实可以省去,我们以原图为基础建立反图,再在这个反图上以 1 1 1为源点跑一次最短路即可。最后一次扫描将答案累加即可。

还有一件比较有趣的事情:我在交不用堆优化的 d i j k s t r a dijkstra dijkstra时不放心开了 O 2 O_2 O2​,结果 M L E MLE MLE了三个点。不开优化又超时,最后靠数组的空间卡过去的。还是老老实实多打点代码吧。

A C   C o d e : \blue{AC \space Code:} AC Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6;
typedef long long LL;

int n,m,v[maxn];
LL ans,d[maxn],fd[maxn];
vector<int> ver[maxn],fver[maxn];
vector<LL> edge[maxn],fedge[maxn];

inline void read()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int u,v;LL w;
		cin>>u>>v>>w;
		ver[u].push_back(v);
		fver[v].push_back(u); 
		edge[u].push_back(w);
		fedge[v].push_back(w);
	}
}

inline void dijkstra()
{
	memset(v,0,sizeof(v));
	memset(d,0x3f,sizeof(d));
	
	d[1]=0;
	for(int i=1;i<n;i++)
	{
		int x=0;
		for(int j=1;j<=n;j++)
		{
			if(!v[j]&&(x==0||d[j]<d[x])) x=j;
		}
		v[x]=1;
		for(int y=0;y<ver[x].size();y++)
		{
			int t=ver[x][y];
			d[t]=min(d[t],d[x]+edge[x][y]);
		}
	}
}

inline void fdijkstra()
{
	memset(v,0,sizeof(v));
	memset(fd,0x3f,sizeof(fd));
	fd[1]=0;
	for(int i=1;i<n;i++)
	{
		int x=0;
		for(int j=1;j<=n;j++)
		{
			if(!v[j]&&(x==0||fd[j]<fd[x])) x=j;	
		}	
		v[x]=1;
		for(int y=0;y<fver[x].size();y++)
		{
			int t=fver[x][y];
			fd[t]=min(fd[t],fd[x]+fedge[x][y]);
		}
	}	
}

int main()
{
	ios::sync_with_stdio(false);
	read();
	dijkstra();
	fdijkstra();
	for(int i=2;i<=n;i++)
	{
		ans+=d[i];
		ans+=fd[i];
	}
	cout<<ans<<endl;
	return 0;
}
上一篇:UVA610 Street Directions


下一篇:memset使用技巧