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

题目描述:

你知道黑暗城堡有 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; 	
}
 
 
 

猜你喜欢

转载自blog.csdn.net/qq_38735931/article/details/84633922
今日推荐