AcWing 4246. 最短路径和(反向建图+链式前向星+堆优化)

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 4246. 最短路径和(反向建图+链式前向星+堆优化)相关的知识,希望对你有一定的参考价值。

题目连接

https://www.acwing.com/problem/content/description/4249/

http://poj.org/problem?id=1511

思路

其实这道题和农场派对这题是一样的,我们反向建边就能求出所有其他点到1这个点的距离,然后直接加上去就好了,但是不同的是这题的数据非常大,所以如果你是使用vector或者其他容器存储的话是会MLE的,所以我们这里手写链式前向星然后每次跑DJ的时候注意初始化就好了,下面放出两种写法的代码(第二种是MLE的)

代码

链式前向星+堆优化Djakarta

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int N=2e6+5;//数据范围
struct edge//存储边
	int u,v,w,next;//u为起点,v为终点,w为权值,next为前继
;
edge e[N];
int head[N],dis[N],n,m,s,cnt;//head为链中最上面的,dis表示当前答案,n为点数,m为边数,s为起点,cnt记录当前边的数量
bool vis[N];//vis表示这个点有没有走过
struct node
	int w,to;//w表示累加的权值,to表示到的地方
	bool operator <(const node &x)const//重载“<”号
		return w>x.w;
	
;

void add(int u,int v,int w)
	++cnt;//增加边的数量
	e[cnt].u=u;//存起点
	e[cnt].v=v;//存终点
	e[cnt].w=w;//存权值
	e[cnt].next=head[u];//存前继
	head[u]=cnt;//更新链最上面的序号
//链式前向星(加边)
void Dijkstra()
	dis[s]=0;//起点到自己距离为0
	priority_queue<node>q;//优先队列(堆优化)
	q.push(node0,s);//压入队列
	while(!q.empty())//队列不为空
		node x=q.top();//取出队列第一个元素
		q.pop();//弹出
		int u=x.to;//求出起点
		if(vis[u]) continue;//已去过就不去了
		vis[u]=true;//标记已去过
		for(int i=head[u];i;i=e[i].next)
			int v=e[i].v;//枚举终点
			if(dis[v]>dis[u]+e[i].w)//若中转后更优,就转
				dis[v]=dis[u]+e[i].w;//更新
				q.push(nodedis[v],v);//压入队列
			
		
	

int U[N],V[N],W[N];

void init()
	int l = max(n,m);
	for(int i = 1;i <= l; ++i) 
		head[i] = 0,vis[i] = false;
		dis[i] = INF;
	
	cnt = 0;


int main()
	int u,v,w = 1;
	s = 1;
	int t;
	scanf("%d",&t);
	while(t--)
		scanf("%d%d",&n,&m);//输入
		init();
		for(int i = 1;i <= m;++i)
			scanf("%d%d%d",&U[i],&V[i],&W[i]);
			add(U[i],V[i],W[i]);
		
		
		Dijkstra();//DJ
		long long ans = 0;
		for(int i = 2;i <= n; ++i)
			ans += dis[i];
		
		init();
		for(int i = 1;i <= m;++i)
			add(V[i],U[i],W[i]);
		
		Dijkstra();
		for(int i = 2;i <= n; ++i)
			ans += dis[i];
		
		printf("%lld\\n",ans);
	
	return 0;


使用容器存储

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
#define PII pair<int,int>
#define INF 0x3f3f3f3f
const int N = 1e6+10;
int dis[N],n,x,m;
struct Node
	int v,w;
;
vector<Node> E[N];
bool vis[N];


void DJ(int s)
	priority_queue<PII,vector<PII>,greater<PII> > que;
	que.push(0,s);
	dis[s] = 0;
	while(!que.empty())
		int t = que.top().second;
		que.pop();
		if(vis[t]) continue;
		vis[t] = true;
		
		for(int i  = 0, l = E[t].size();i < l; ++i) 
			int j = E[t][i].v;
			int w = E[t][i].w;
			if(dis[j] > dis[t] + w)
				dis[j] = dis[t] + w;
				que.push(dis[j],j);
			
		
	


void init()
	for(int i = 1;i <= n; ++i) vis[i] = false,dis[i] = INF;
	for(int i = 1;i <= n; ++i) E[i].clear();


int U[N],V[N],W[N];
int main()

	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int t;
	cin>>t;
	while(t--)
		cin>>n>>m;
		int u,v,w;
		init();
		for(int i = 1;i <= m; ++i)
			cin>>U[i]>>V[i]>>W[i];
			E[U[i]].push_back(V[i],W[i]);//正向建图
			E[v].push_back(u,w);//反向建图
		
		long long ans = 0;
		DJ(1);
		for(int i = 1;i <= n; ++i)
			ans += dis[i];
		
		init();
		for(int i = 1;i <= m; ++i)
			E[V[i]].push_back(U[i],W[i]);//反向建图
		DJ(1);
		for(int i = 1;i <= n; ++i)
			ans += dis[i];
		cout<<ans<<endl;
	
	
	
	return 0;   


以上是关于AcWing 4246. 最短路径和(反向建图+链式前向星+堆优化)的主要内容,如果未能解决你的问题,请参考以下文章

P1629 邮递员送信最短路+反向建图

hdu3499(分层图最短路 or 反向建图)

AcWing 1132. 农场派对(最短路反向建边)

920. 最优乘车根据题意建图求最短路

AcWing1131 拯救大兵瑞恩(最短路)

图的最短路径和拓扑排序