最短路+次短路长度与条数模板

题目是HDU-1688

传送门

模板:

#include<bits/stdc++.h>
#define N 1005
#define M 10005
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
int t,c,S,F,n,m;
int head[N],dis[N][2],num[N][2];//0表示最短路,1表示次短路,分别表示最短路次短路的距离,最短路次短路有多少条
bool vis[N][2];//0表示最短路是否走过,1表示次短路是否走过
struct ljh
{
	int to,next,w;
}e[M];
struct xqy
{
	int x,d,id;
	xqy(int x=0,int d=0,int id=0):x(x),d(d),id(id){}
	bool operator < (const xqy&a)const
	{
		return a.d<d;
	}
};
inline void add(int x,int y,int z)
{
	e[c].next=head[x];
	e[c].to=y;
	e[c].w=z;
	head[x]=c++;
}
void Dij(int s)
{
	for(int i=1;i<=n;i++)dis[i][0]=dis[i][1]=INF;
	memset(vis,0,sizeof(vis));
	memset(num,0,sizeof(num));
	dis[s][0]=0;
	num[s][0]=1;
	priority_queue<xqy>q;
	q.push(xqy(s,0,0));
	while(!q.empty())
	{
		xqy now=q.top();
		q.pop();
		int x=now.x;
		int id=now.id;
		if(vis[x][id])continue;
		vis[x][id]=1;
		for(int i=head[x];i!=-1;i=e[i].next)
		{
			int nex=e[i].to;
			int temp=now.d+e[i].w;
			// cout<<temp<<endl;
			if(dis[nex][0]>temp)//比较最短路,比最短路小
			{
				dis[nex][1]=dis[nex][0];
				num[nex][1]=num[nex][0];
				q.push(xqy(nex,dis[nex][1],1));
				dis[nex][0]=temp;
				num[nex][0]=num[x][0];
				q.push(xqy(nex,dis[nex][0],0));
			}
			else if(dis[nex][0]==temp)//等于最短路
			{
				num[nex][0]+=num[x][0];//相同的一条路,只会由最短路走过来
			}
			else if(dis[nex][1]>temp)//比次短路小
			{
				dis[nex][1]=temp;
				num[nex][1]=num[x][id];//因为他也可能是由之前的最短路走出来的次短路
				q.push(xqy(nex,dis[nex][1],1));
			}
			else if(dis[nex][1]==temp)
			{
				num[nex][1]+=num[x][id];
			}

		}
	}
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		c=0;
		memset(head,-1,sizeof(head));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add(x,y,z);
		}
		scanf("%d%d",&S,&F);
		Dij(S);
		// cout<<dis[F][0]<<" "<<dis[F][1]<<endl;
		if(dis[F][0]+1==dis[F][1])printf("%d\n",num[F][0]+num[F][1]);
		else printf("%d\n",num[F][0]);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值