poj3463 最短路+次短路

链接:http://poj.org/problem?id=3463

题意:给定一个图和起点S、终点F,求最短路的数量和比最短路大1的路径的数量。

题解:建立二维dijk数组,分别为最短路和次短路,若最短路比次短路小1,则输出它们的数量。

dis[0][i]描述最短路径,dis[1][i]描述次短路径的长度,way[0][i],way[1][i]分别描述最短路、次短路的数量。

check[0][i]\check[1][i]为标号。

由于采用dijk思想,所以每次从堆里出来的必定是最短路,或者是次短路(当最短路已出来时)。

1、每次从没有被标记过的dis[][]中选出最小值,记录该点v

2、更新与v点相连的点的dis值和way值。

3、2n-1个循环(每一个循环算出一个dis[][]值)

4、有重边,用邻接表。

 

#include<stdio.h>	
#include<string.h>
#define M 1000000
int dis[2][1200],way[2][1200],check[2][1200];
int adj[1200];
int n,m;
struct aa
{
	int to,w,next;
}map[10020];

void dijk(int s)
{
	int i,j;
	int u,v,min;
	int k,w,c;
	memset(check,0,sizeof(check));
	memset(way,0,sizeof(way));
	for(i=0;i<=1;i++)
		for(j=1;j<=n;j++)
			dis[i][j]=M;
	dis[0][s]=0;way[0][s]=1;
	for(i=1;i<2*n;i++)
	{
		for(j=1,min=M;j<=n;j++)         //从dis[][]中找出权值最小且未被走过的一个,走该路径
		{
			if(check[0][j]==0&&dis[0][j]<min)
			{
				u=0;v=j;
				min=dis[0][j];
			}
			if(check[1][j]==0&&dis[1][j]<min)
			{
				u=1;v=j;
				min=dis[1][j];
			}
		}
		check[u][v]=1;
		//找出该点v后,更新与它相邻的点的dis值
		//if 比dis[0][v]小,则最小为次小,该值为最小,更新最短和次短的way
		//else if 与dis[0][v]相等,则way+
		//else if 小于dis[1][v],则该值为次短,更新way
		//else if 等于dis[1][v],way+
		for(j=adj[v];j!=-1;j=map[j].next)
		{
			k=map[j].to;w=map[j].w;
			c=dis[u][v]+w;
			if(c<dis[0][k])
			{
				dis[1][k]=dis[0][k];
				way[1][k]=way[0][k];
				dis[0][k]=c;
				way[0][k]=way[u][v];
			}
			else
				if(c==dis[0][k])
					way[0][k]+=way[u][v];
				else
					if(c<dis[1][k])
					{
						dis[1][k]=c;
						way[1][k]=way[u][v];
					}
					else
						if(c==dis[1][k])
							way[1][k]+=way[u][v];
		}
	}
}
int main()
{
	int i,j,t;
	int a,b,c;
	int s,e;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		memset(adj,-1,sizeof(adj));
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			map[i].to=b;map[i].w=c;map[i].next=adj[a];adj[a]=i;
		}
		
		scanf("%d%d",&s,&e);
		dijk(s);
		if(dis[1][e]==dis[0][e]+1)
			way[0][e]+=way[1][e];
		printf("%d\n",way[0][e]);

	}
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值