D94 最短路径树 BFS 算法 CF1005F Berland and the Shortest Paths

D94 最短路径树 BFS 算法 CF1005F Berland and the Shortest Paths_哔哩哔哩_bilibili

 

CF1005F Berland and the Shortest Paths - 洛谷

给定一个 个点,条边的无向简单连通图,每条边权为 1,求最短路径树的方案数,并输出 k 种方案

思路

最短路计数问题,由于每个边的边权为 1 ,求最短路径树的 Dijkstra 算法退化为广搜(BFS)

一个点的所有前驱边都是平权的,所以对每个点维护一个前驱边的编号集 pre[v],

这样总的方案数就是所有点集合大小的乘积,然后用 DFS 在每个集合中选一个前驱边输出

图中节点 2,3 均有一条前驱边,节点 4,5 均有两条前驱边,所以方案数为 $1*1*2*2=4$

四种方案遍历回溯得出(红数字代表边的编号):111010,111001,110110,110101

如果方案数大于 k 值,直接取 k 种;如果方案数小于 k 值,搜完即终止

image

相关板子:

D92【模板】最短路径树 Dijkstra 算法 CF545E Paths and Trees - 董晓 - 博客园

 

// 最短路径树 BFS 算法 O(N+M)
#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;
int idx,h[N],to[N<<1],ne[N<<1],id[N<<1];
void add(int a,int b,int c){
  to[++idx]=b;id[idx]=c;ne[idx]=h[a];h[a]=idx;
}
int n,m,k,sum,tot=1,d[N]; bool vis[N];
vector<int> pre[N];

void bfs(int s){
  queue<int> q;
  q.push(s); d[s]=0;
  while(!q.empty()){
    int u=q.front(); q.pop();
    for(int i=h[u];i;i=ne[i]){
      int v=to[i],w=id[i];
      if(!d[v]){
        d[v]=d[u]+1;
        pre[v].push_back(w); //保存v的前驱边编号
        q.push(v);
      }
      else if(d[v]==d[u]+1) pre[v].push_back(w);
    }
  }
}
void dfs(int x){ //输出tot种方案
  if(x==n+1){
    for(int i=1;i<=m;++i)printf("%d",vis[i]); //输出方案
    puts("");
    if(++sum==tot) exit(0);
    return;
  }
  for(int i=0;i<pre[x].size();++i){
    vis[pre[x][i]]=1; //选x的第i个前驱边
    dfs(x+1);         //枚举点2,3,4,...,n
    vis[pre[x][i]]=0; //不选
  }
}
signed main(){
  scanf("%d%d%d",&n,&m,&k);
  for(int i=1,x,y;i<=m;++i){
    scanf("%d%d",&x,&y);
    add(x,y,i),add(y,x,i);
  }
  
  bfs(1);
  for(int i=2;i<=n;++i){
    if(tot*pre[i].size()>k){tot=k;break;} 
    else tot*=pre[i].size();
  }
  printf("%d\n",tot); //方案数
  dfs(2);
}

 

P10929 黑暗城堡 - 洛谷

有边权的无向图,求最短路径树的方案数

思路

同样的思路,用 cnt[v] 记录节点的最短路方案数,最后乘起来就行了

// 最短路径树 Dijkstra 算法 O(MlogN)
#include<bits/stdc++.h>
#define ll long long
#define pli pair<ll,int>
using namespace std;

const int N=1010,M=N*N;
const ll mod=2147483647;
int h[N],to[M],ne[M],idx; ll ww[M];
void add(int a,int b,ll c){
  to[++idx]=b,ww[idx]=c,ne[idx]=h[a],h[a]=idx;
}
int n,m;
ll d[N],cnt[N]; bool vis[N];

void dijkstra(){
  for(int i=1; i<=n; i++) d[i]=1e18; d[1]=0;
  priority_queue<pli,vector<pli>,greater<pli> >q;
  q.push({0,1});
  while(!q.empty()){
    auto u=q.top().second; q.pop();
    if(vis[u]) continue; vis[u]=1;
    for(int i=h[u]; i; i=ne[i]){
      int v=to[i],w=ww[i];
      if(d[v]>d[u]+w){
        d[v]=d[u]+w;
        q.push({d[v],v});
        cnt[v]=1;
      }
      else if(d[v]==d[u]+w) cnt[v]++;
    }
  }
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=0; i<m; i++){
    int a,b; ll c;
    scanf("%d%d%lld",&a,&b,&c);
    add(a,b,c),add(b,a,c);
  }
  dijkstra();
  ll ans=1;
  for(int i=2; i<=n; i++) ans=ans*cnt[i]%mod;
  printf("%lld\n",ans);
}

 

posted @ 2026-03-05 15:38  董晓  阅读(39)  评论(0)    收藏  举报