洛谷P1608 路径统计(最短路数统计)

洛谷P1608 路径统计

这一道题是P1144的加强版,我们先来看看P1144是如何求解的:
题目要求的是求出每个顶点所对应的最短路径的条数,而这道题中边的权值都为1,所以和最短路联系起来的话不难想到可以用BFS。
但是毕竟我刚学了最短路系列算法怎么可能不用呢,所以在P1144中采用了Dijkstra算法 其实完全没必要,实现了后发现和BFS没啥区别
主要思想: 到第i个顶点的最短路径是第i个顶点的所有前趋顶点(就是从起点到i的最短路径上i的前一个顶点)最短路径条数之和(有点动态规划的赶脚了)
由于Dijkstra是按每个顶点最短路径的长度从小到大遍历,所以保证了求第i个顶点的最短路径的时候它的前趋顶点的最短路径都被求出了(实际上是动态规划的思想,无后效性),而且又因为每条边只会被遍历一次,所以可以想到用Dijkstra算法在遍历边的时候做一些手脚,就可以求出第i个顶点的最短路条数:

利用数组来记录每个顶点的最短路条数,遍历边时,如果下一顶点对应的花费d[a]和当前路径的花费d[v]+1相同那么就加上当前顶点的
最短路条数,如果比当前路径大,那么说明下一顶点之前的路径并非是最短路径,这时我们就需要更新顶点值和它对应的最短路径条数

这一部分的代码:

for(int i=0;i<g[v].size();i++)	//边的遍历,v是当前所取的顶点
		{
			int &a=g[v][i];	//下一个顶点
			if(d[v]+1<d[a])	//如果小于则更新
			{
				d[a]=d[v]+1;
				que.push(P(d[a],a));		//最普通的dijkstra
				ways[a]=ways[v];//路径长度重置,路径条数也要重置
			}
			else
			if(d[v]+1==d[a])ways[a]+=ways[v];//当前路径与之相等则加上
			ways[a]%=MOD;//每次都mod一下以免爆掉
		}

完整代码:

#include
#include
#include
#include
#include
using namespace std;
const int MAX_N=1e6+1;
const int MOD=100003;
typedef pair<int,int> P;
int d[MAX_N],ways[MAX_N];		//ways数组记录最短路条数
inline int read()
{
	int sum=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){sum=(sum<<1)+(sum<<3)+c-48;c=getchar();}
	return sum*f;
}
int main()
{
	int n,m;
	n=read(),m=read();
	int from,to;
	vector<int> g[n+1];
	for(int i=0;i<m;i++)
	{
		from=read(),to=read();
		if(from==to)continue;		//自环没有影响,直接去掉
		g[from].push_back(to);
		g[to].push_back(from);
	}
	priority_queue<P,vector<P>, greater<P> > que;
	que.push(P(0,1));
	fill(d,d+n+1,MAX_N);//dijkstra算法准备工作得做好
	d[1]=0;
	ways[1]=1;			//记得把第一个顶点的最短路数设为1
	while(!que.empty())
	{
		P p=que.top();
		que.pop();
		int value=p.first,v=p.second;
		if(value>d[v])continue;
		for(int i=0;i<g[v].size();i++)
		{
			int &a=g[v][i];
			if(d[v]+1<d[a])
			{
				d[a]=d[v]+1;
				que.push(P(d[a],a));
				ways[a]=ways[v];		
			}
			else
			if(d[v]+1==d[a])ways[a]+=ways[v];
			ways[a]%=MOD;
		}
	} 
	for(int i=1;i<=n;i++)printf("%d\n",ways[i]%MOD);
	return 0;
}

再来看P1608路径统计,实际上和这个一样就是边的权值不是1了,我们只需要把权值加入进去就行了,另外本题主要是数据有点儿坑,要手动排除重复边(权值相同),还有就是会有重边(权值不同),但是因为是最短路问题,所以只需要取所有重边中权值最小的就行
完整代码:

#include
#include
#include
#include
#include
using namespace std;
const int MAX_N=2e3+1;
typedef pair<int,int> P;
int d[MAX_N],ways[MAX_N];
char dist[MAX_N][MAX_N];
inline int read()
{
	int sum=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){sum=(sum<<1)+(sum<<3)+c-48;c=getchar();}
	return sum*f;
}
int main()
{
	int n,m;
	n=read(),m=read();
	int from,to,cost;
	vector<P> g[n+1];
	for(int i=0;i<m;i++)
	{
		from=read(),to=read(),cost=read();
		if(dist[from][to]>cost||!dist[from][to])
		{
			g[from].push_back(P(to,cost));
			dist[from][to]=cost;
		}
	}
	priority_queue<P,vector<P>, greater<P> > que;
	que.push(P(0,1));
	fill(d,d+n+1,(int)1e9);
	d[1]=0;
	ways[1]=1;
	while(!que.empty())
	{
		P p=que.top();
		que.pop();
		int value=p.first,v=p.second;
		if(value>d[v])continue;
		for(int i=0;i<g[v].size();i++)
		{
			P k=g[v][i];
			cost=k.second;
			int a=k.first;
			if(d[v]+cost<d[a])		//同P1144只是权值不是固定的1
			{
				d[a]=d[v]+cost;
				que.push(P(d[a],a));
				ways[a]=ways[v];
			}
			else
			if(d[v]+cost==d[a])ways[a]+=ways[v];
		}
	}
	if(ways[n])
	{
		cout<<d[n]<<" "<<ways[n];
	}
	else cout<<"No answer";
	return 0;
}

你可能感兴趣的:(最短路算法)