【洛谷】P1144 最短路计数(图论、bfs、dp)

题目描述

【洛谷】P1144 最短路计数(图论、bfs、dp)_第1张图片【洛谷】P1144 最短路计数(图论、bfs、dp)_第2张图片

解析

先上一张样例的图>_<

【洛谷】P1144 最短路计数(图论、bfs、dp)_第3张图片

  1. 对图进行宽度优先搜索(bfs),可以得到一个搜索树。把1当作根节点,定义这棵搜索树中与根节点距离相同(即边数相同)的点属于同一层。对于一个点x,距离比少一条边的点都是它的上一层。如上图中相同颜色属于相同层,不同颜色属于不同层。
  2. 由于是无向无权图,bfs搜索树的层数就是该节点的最短路径。每一层的节点都由它的上一层拓展而来,于是可以知道某个结点x的最短路径总数等于上一层中所有能够到达x的节点的最短路径总数之和。令dp[x]表示1到x的最短路径树,则dp[x]= ∑ i \displaystyle\sum_{i} idp[ y i y_{i} yi], y i y_{i} yi是x上一层中所有与x相连的点(此处有点dp的思想,由于是逐层扩展,所以满足了dp的无后效性)。
  3. 具体实现:bfs遍历图的过程中,用vis[x]记录点x的层数(假设根节点的层数为1,vis数组初始化为0),由点u扩展到一个未访问过的v点时,v层数更新为vis[u]+1。假如u的出边v已经访问过且它是v的下一层,则dp[v]+=dp[u]。在bfs遍历时逐层更新dp数组就可以得到答案。另外,自环对于最短路没有影响可以不储存。而重边和其它边对最短路径数的影响是一样的,不用做特别处理。

AC代码

#include
#include
#include
#include
#include
   using namespace std;
   const int maxM=2e6+10;  / /最大边数
   const int maxN=1e6+10;  / /最大点数
   const int mod=100003;  
   struct edge{
     
   	int u;
   	int v;
   	int w;
   	int next;
   }e[maxM];  / /邻接表存图
   int head[maxM];
   int vis[maxN];  / /记录点的层数,vis[x]表示x的层数,vis[x]0表示x未被访问
   int dp[maxN];  / /dp[x]表示点1到x的最短路径数
   int cnt=0;    / /统计边数
   void insert(int u,int v){
         / /邻接表存图的加边函数
    cnt++;	
    e[cnt].u =u;
    e[cnt].v =v;
	e[cnt].next=head[u];
	head[u]=cnt;
   }
   queue<int>que;
   void bfs(int cur){
       / /bfs的过程中更新dp数组
   vis[cur]=1;	     / /标记已访问
   que.push(cur);	/ /1入队
   while(!que.empty()){
     	
   int u=que.front();  
    que.pop();	
   for(int i=head[u];i>0;i=e[i].next){
     
   if(!vis[e[i].v]){
       / /u的出边v没有访问过的话,节点入队,更新节点层数vis[]和最短路径数dp[]
   que.push(e[i].v);
   vis[ e[i].v ]=vis[u]+1;
   dp[e[i].v]+=dp[u]%mod;                        
         }	
   else if(vis[e[i].v]==vis[u]+1)  / /已经访问过且u是v的上一层时更新最短路径数dp[]
   dp[e[i].v]+=dp[u]%mod; 
      }		
      }
   }
   int main(){
     
   memset(head,-1,sizeof(head));
   memset(vis,0,sizeof(vis));
   memset(dp,0,sizeof(dp));
   int N,M;
   scanf("%d%d",&N,&M);
   for(int i=1;i<=M;i++){
      / /读入边
   int u,v;
   scanf("%d%d",&u,&v);
   if(u!=v)  {
        / /细节:自环对于最短路没有影响可以不储存
   insert(u,v);   / /注意无向图要存两遍
   insert(v,u);
   }
   }
   dp[1]=1;
   bfs(1);
   for(int i=1;i<=N;i++) printf("%d\n",dp[i]%mod);	
   return 0;	
   } 

你可能感兴趣的:(图论,bfs,动态规划,算法,c++)