《算法竞赛进阶指南》0x62 T4 黑暗城堡

题目传送门

题目描述

在顺利攻破 Lord lsp 的防线之后,lqr 一行人来到了 Lord lsp 的城堡下方。

Lord lsp 黑化之后虽然拥有了强大的超能力,能够用意念力制造建筑物,但是智商水平却没怎么增加。

现在 lqr 已经搞清楚黑暗城堡有 N 个房间,M 条可以制造的双向通道,以及每条通道的长度。

lqr 深知 Lord lsp 的想法,为了避免每次都要琢磨两个房间之间的最短路径,Lord lsp 一定会把城堡修建成树形的。

但是,为了尽量提高自己的移动效率,Lord lsp 一定会使得城堡满足下面的条件:

设 D[i] 为如果所有的通道都被修建,第 i 号房间与第 1 号房间的最短路径长度;而 S[i] 为实际修建的树形城堡中第 i 号房间与第 1 号房间的路径长度;要求对于所有整数 i,有 S[i]=D[i] 成立。

为了打败 Lord lsp,lqr 想知道有多少种不同的城堡修建方案。

你需要输出答案对 231–1 取模之后的结果。

输入格式

第一行有两个整数 N 和 M。

之后 M 行,每行三个整数 X,Y 和 L,表示可以修建 X 和 Y 之间的一条长度为 L 的通道。

输出格式

一个整数,表示答案对 231–1 取模之后的结果。

数据范围

2 ≤ N ≤ 1000 , 2≤N≤1000, 2≤N≤1000,
N − 1 ≤ M ≤ N ( N − 1 ) / 2 , N−1≤M≤N(N−1)/2, N−1≤M≤N(N−1)/2,
1 ≤ L ≤ 100 1≤L≤100 1≤L≤100

输入样例:

3 3
1 2 2
1 3 1
2 3 1

输出样例:

2

题解

这道题目实际上就是要求最短路径生成树的数量
首先引出一个概念,什么是最短路径生成树?
即在我们生成的这棵树中,从源点到每个点的路径与在无向图之中源点到每个点的最短路大小相等
因此我们首先需要知道在无向图中,源点到每个点的最短路大小
跑一遍Dijkstra就ok了
我们可以遍历每条边,如果 d i s [ x ] + e d g e [ i ] . v a l dis[x]+edge[i].val dis[x]+edge[i].val恰好等于 d i s [ y ] dis[y] dis[y],那么我们就可以有一种到达节点 y y y的路径,可以统计有到达每个节点的路径有多少种,即每当满足上述条件,我们使 c n t [ y ] + + cnt[y]++ cnt[y]++,根据乘法原理,将到达每个节点路径数相乘,即为可以生成的最小路径生成树的数量

code
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
const int M=N*(N-1)/2;
int n,m;
struct node
{
	int nxt,to,val;
}edge[2*M];
int head[N],tot=0;
void Lian(int x,int y,int z)
{
	tot++;
	edge[tot].to=y;
	edge[tot].nxt=head[x];
	edge[tot].val=z;
	head[x]=tot;
}
struct Point
{
	int d,p;
	bool operator<(const Point &x)const{
		return d>x.d;	
	}
};
int dis[N];
bool vis[N];
void dijkstra()
{
	memset(dis,0x3f,sizeof(dis));
	priority_queue<Point> q;
	dis[1]=0;
	Point a;
	a.d=0,a.p=1;
	q.push(a);
	while(!q.empty())
	{
		a=q.top();
		q.pop();
		int x=a.p;
		if(vis[x]) continue;
		vis[x]=1;
		for(int i=head[x];i;i=edge[i].nxt)
		{
			int y=edge[i].to;
			if(dis[x]+edge[i].val<dis[y])
			{
				dis[y]=edge[i].val+dis[x];
				a.p=y,a.d=dis[y];
				q.push(a);
			}
		}
	}
}
long long cnt[N];
const int Mod=(1<<31)-1;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y,l;
		scanf("%d%d%d",&x,&y,&l);
		Lian(x,y,l);
		Lian(y,x,l);
	}
	dijkstra();
	cnt[1]=1;
	for(int i=1;i<=n;i++)
		for(int j=head[i];j;j=edge[j].nxt)
		{
			int y=edge[j].to;
			if(dis[i]+edge[j].val==dis[y]) cnt[y]++;
		}
	long long ans=1;
	for(int i=1;i<=n;i++) ans=ans*cnt[i]%Mod;
	cout<<ans;
	return 0;
 } 
上一篇:CF1523B Lord of the Values(构造+思维)


下一篇:VulnHub靶场篇7-Lord Of The Root: 1.0.1