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<iostream>
#include<queue>
#include<vector>
#include<cstdio>
#include<utility>
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<iostream>
#include<queue>
#include<vector>
#include<cstdio>
#include<utility>
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;
}