一句话题意:
给出一张无向图,求它的以1为根的最短路径生成树个数。
(答案对2147483647取模)
按说这题是放在最小生成树一章里面的,正解也应该是最小生成树之类的东西。
然而我太弱了,并不会用最小生成树解这题。
(以下的瞎扯如果有错的,欢迎在评论区批评指正orz)
算法一:乱搞
首先,既然是求最短路径树的个数,我们肯定要用到最短路径。
所以以1为起点跑一遍最短路,dijkstra和spfa都可以。
我们应该如何统计答案呢?
首先我们可以很容易地想到,在原图中,与最短路径无关的边是不参与答案统计的。
那么与最短路径有关的边是如何参与答案统计的呢?
扫描二维码关注公众号,回复:
7182055 查看本文章
首先我们知道,每一条与最短路径有关的边都可以参与最短路径树的生成。
其次我们知道,最短路径树是一个完整的连通块。
我们假设有一个最短路径树,现在将它的其中一个叶子节点割掉。
考虑如何将它重新变为一棵最短路径树。
很显然,每一个指向那个节点的最短路径边都可以做到这件事情,答案是形成那个被割掉的树的方案数乘以那个叶子节点的入度。
反过来思考,最短路径树的形成实际上就是一个递归过程,每个节点(除了根节点1)都要收到同样的待遇。
所以答案就是所有节点(除了1)关于最短路径边的入度乘起来。
哦对了,无向边要割成两条有向边处理。
下面附上我丑陋的代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 struct node{ 7 int to,next,len; 8 }e[1000005]; 9 10 int cnt=0,n,m; 11 int head[1005],dis[1005][2],xx[500005],yy[500005],ll[500005]; 12 long long int statistics[1005]; 13 bool vis[1005]; 14 15 void add(int from,int to,int len){ 16 e[++cnt].to=to; 17 e[cnt].len=len; 18 e[cnt].next=head[from]; 19 head[from]=cnt; 20 } 21 22 inline void spfa(bool statue){ 23 queue<int> q; 24 q.push(1); 25 dis[1][statue]=0; 26 vis[1]=1; 27 28 while(!q.empty()){ 29 int now=q.front(); 30 vis[now]=0; 31 q.pop(); 32 33 for(int i=head[now];i;i=e[i].next){ 34 if(dis[e[i].to][statue]>dis[now][statue]+e[i].len){ 35 dis[e[i].to][statue]=dis[now][statue]+e[i].len; 36 if(vis[e[i].to]==0){ 37 vis[e[i].to]=1; 38 q.push(e[i].to); 39 } 40 } 41 } 42 } 43 } 44 45 void handle(){ 46 for(int i=1;i<=m;i++){ 47 if(dis[xx[i]][0]==dis[yy[i]][0]+ll[i]) statistics[xx[i]]++; 48 if(dis[yy[i]][0]==dis[xx[i]][0]+ll[i]) statistics[yy[i]]++; 49 } 50 } 51 52 int main(void){ 53 memset(dis,0x3f,sizeof(dis)); 54 55 scanf("%d%d",&n,&m); 56 for(int i=1;i<=m;i++){ 57 int x,y,l; 58 scanf("%d%d%d",&x,&y,&l); 59 add(x,y,l); 60 add(y,x,l); 61 xx[i]=x,yy[i]=y,ll[i]=l; 62 } 63 64 spfa(0); 65 handle(); 66 67 long long int ans=1; 68 for(int i=2;i<=n;i++) ans*=statistics[i],ans%=(1ll<<31)-1; 69 printf("%lld",ans); 70 }
未完待续。。。