当前位置: 代码迷 >> 综合 >> 【loj】#10064. 「一本通 3.1 例 1」黑暗城堡(最短路径生成树 dijkstra+Prim)
  详细解决方案

【loj】#10064. 「一本通 3.1 例 1」黑暗城堡(最短路径生成树 dijkstra+Prim)

热度:41   发布时间:2023-12-26 09:51:03.0

题目描述:

你知道黑暗城堡有 N个房间,M 条可以制造的双向通道,以及每条通道的长度。

城堡是树形的并且满足下面的条件:

设 Di? 为如果所有的通道都被修建,第 i 号房间与第 1 号房间的最短路径长度;

而 Si? 为实际修建的树形城堡中第 i 号房间与第 1 号房间的路径长度;

要求对于所有整数 i (1≤i≤N),有 Si=Di? 成立。

你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对 2^31?1取模之后的结果就行了。

题目链接:https://loj.ac/problem/10064
 

【分析】先用dijkstra求出1号房间到每个房间的单源最短路径存储到dis数组中。把树形城堡看作以1为根的有根树。由题,若x是y的根节点,x、y之间的通道长度为z,则应该有:dis[y]=dis[x]+z。事实上,我们把满足题目要求的树结构,即对任意一对父子结点x、y都有上式成立的树结构,称为图的一棵最短路径生成树。与Prim算法类似,统计有多少结点x满足dis[p]=dis[x]+e[x][p],让p与其中任意一个x相连都符合题目要求。

【注意】

  • 最短路径生成树:对于任意一对父子结点x、y均满足dis[y]=dis[x]+e[x][y]的树结构称为图的一棵最短路径生成树;
  • 在宏定义中!! 2^31-1 写为  (1<<31)-1  要加括号!! 要加括号!! 不然就会wa好多好多次了...
  • 然后,不要忘了给e数组初始化....不然就默认为0了..
  • 这题数据范围比较小,所以可以用邻接矩阵,不过这个是树,稀疏图,一般是用邻接表的。

【代码】

#include<bits/stdc++.h>
using namespace std;typedef long long ll;
const int maxn=1e3+5;
const int inf=0x3f;
const ll mod=(1<<31)-1;//注意括号!!优先级!!int e[maxn][maxn];//存边
int dis[maxn];//存单源最短路径
int vis[maxn];int n,m;void Dijkstra()
{memset(dis,inf,sizeof(dis)); memset(vis,0,sizeof(vis));dis[1]=0;while(1){int now=-1;for(int i=1;i<=n;i++)if(!vis[i])if(now==-1 || dis[i]<dis[now])now=i;if(now==-1)break;vis[now]=1;for(int i=1;i<=n;i++)if(e[now][i]!=inf)dis[i]=min(dis[i],dis[now]+e[now][i]);}
}
int main()
{scanf("%d%d",&n,&m);memset(e,inf,sizeof(e));//不要忘了初始化for(int i=1;i<=m;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);e[x][y]=e[y][x]=min(e[x][y],w);//这里如果有重边的时候,要存最小值!!避免覆盖 }Dijkstra();ll ans=1;for(int i=2;i<=n;i++){int cnt=0;for(int j=1;j<=n;j++)if(e[j][i]!=inf)if(dis[j]+e[j][i]==dis[i])cnt++;ans=(ans*cnt)%mod;}printf("%lld\n",ans);return 0; 	
}