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

题目描述

在这里插入图片描述在这里插入图片描述

解析

先上一张样例的图>_<

在这里插入图片描述

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

猜你喜欢

转载自blog.csdn.net/IAMLSL/article/details/108394437
今日推荐