Acwing 383. 观光 算法竞赛进阶指南

题意分析

从起点到终点,最短路径的条数和比最短路径多一个长度的条数之和

算法分析

最短路径的条数:在更新最短路时,如果遇到dist[j]=dist[i]+w的情况时,此时cnt(记录最短路条数)的数量进行更新cnt+=count

比最短路径多一个长度的条数:边权为整数,比最短路大1,即在次短路中寻找比最短路长度少1的条数就行累加

综上,本题的根本是求最短路与次短路

利用dij计算最短路,同时也把次短路一起算出来:
用两个变量分别存储最小值和次小值,遍历到新的最小值时,把当前最小值设为次小值,原次小值丢弃,然后再设置新的最小值;遍历到无法更新最小值但可以更新次小值的值时,把它设为次小值。

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=20010;
int n,m,s,t;
int cnt[N][2],dist[N][2];//d[i][0]存储1~i最短路, d[i][1]存储1~i次短路
bool st[N][2];


//对于每个点记录三个信息,pair不够用,用struct

struct ver{
	int id,type,dist;//对于每个点记录标号,最短路/次短路,距离 
	bool operator> (const ver &w) const
    {
    	return dist>w.dist; 
	}
}; 

int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
	e[idx]=b;
	w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}

int dij()
{
	memset(st,0,sizeof st);
	memset(dist,0x3f,sizeof dist);
	memset(cnt,0,sizeof cnt);
	
	//对于源点只有最短路,没有次短路 
	dist[s][0]=0;//源点的最短路距离为0 
	cnt[s][0]=1;//源点的最短路条数为1
	
	priority_queue<ver,vector<ver>,greater<ver> >q;
	q.push({s,0,0});
	 
	while(q.size())
	{
		ver t=q.top();
		q.pop();
		
		int tver=t.id,ttype=t.type,distance=t.dist,count=cnt[tver][ttype];
		
		if(st[tver][ttype])  continue;
		st[tver][ttype]=true;
		
		for(int i=h[tver];~i;i=ne[i]) 
		{
			int j=e[i];
			//有更短得最短路 
			if(dist[j][0]>distance+w[i])
			{
				//把当前最短路得值先给次短路 
				dist[j][1]=dist[j][0]; 
				cnt[j][1]=cnt[j][0];
				q.push({j,1,dist[j][1]});
				//更新最短路
				dist[j][0]=distance+w[i];
				cnt[j][0]=count;
				q.push({j,0,dist[j][0]}); 
			}
			//
			else if(dist[j][0]==distance+w[i])
			{
				cnt[j][0]+=count;
			 } 
			 //当前新值大于最短路,小于次短路, 
			 else if(dist[j][1]>distance+w[i])
			 {
			 	dist[j][1]=distance+w[i];
				 cnt[j][1]=count;
				 q.push({j,1,dist[j][1]}); 
			 }
			 else if(dist[j][1]==distance+w[i])
			 {
			 	cnt[j][1]+=count;
			 }
		}
    	
	}
	int res=cnt[t][0];
	if(dist[t][0]+1 == dist[t][1])  res+=cnt[t][1];
	return res;
 } 

int main()
{
	ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int ts;
    cin>>ts;
    while(ts--)
    {
    	
    	cin>>n>>m;
    	memset(h,-1,sizeof h);
    	idx=0; 
    	while(m--)
    	{
    		int a,b,c;
    		cin>>a>>b>>c;
    		add(a,b,c);
		}
		cin>>s>>t;
		cout<<dij()<<endl;
	}
	return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值