6202 黑暗城堡 0x60「图论」例题
描述:
在顺利攻破Lord lsp的防线之后,lqr一行人来到了Lord lsp的城堡下方。Lord lsp黑化之后
虽然拥有了强大的超能力,能够用意念力制造建筑物,但是智商水平却没怎么增加。现在
lqr已经搞清楚黑暗城堡有N个房间 (1≤N≤1000),M条可以制造的双向通道,以及每条通道
的长度。
lqr深知Lord lsp的想法,为了避免每次都要琢磨两个房间之间的最短路径,Lord lsp一定会把城堡修建成树形的;但是,为了尽量提高自己的移动效率,Lord lsp一定会使得城堡满足
下面的条件:设 D[i] 为如果所有的通道都被修建,第 i 号房间与第1号房间的最短路径长度;
而 S[i] 为实际修建的树形城堡中第 i 号房间与第1号房间的路径长度;要求对于所有整数 i(1
≤i≤N),有 S[i]=D[i] 成立。
为了打败Lord lsp,lqr想知道有多少种不同的城堡修建方案。于是lqr向applepi提出了这个问题。因为applepi还要忙着出模拟赛,所以这个任务就交给你了。当然,你只需要输出答案对 2^31–1
取模之后的结果就行了。
输入格式
第一行有两个整数N 和M。
之后M 行,每行三个整数X,Y 和L,表示可以修建X 和Y 之间的一条长度为L 的通道。输出格式
一个整数,表示答案对 2^31–1 取模之后的结果。
样例输入
3 3 1 2 2 1 3 1 2 3 1 样例输出 2 数据范围与约定 *对于30% 的数据,2≤N≤5,M≤10。 对于50% 的数据,满足条件的方案数不超过10000。 对于100% 的数据,2≤N≤1000,N – 1≤M≤N(N – 1)/2,1≤L≤100。
题目链接:
http://contest-hunter.org:83/contest/0x60%E3%80%8C%E5%9B%BE%E8%AE%BA
题意:求在一张无向图中用到达各点的最短路生成的树一共可以有多少颗。
分析:
区别最小生成树,用最短路构成的数不一定是最小生成树,最小生成树也不一定由最短路们构成。
运用乘法原理,我们只需要求出到达图中某点的路径中路径长度等于最短路长度的有多少条,并将其
叠乘进ans中即可。
所以现用二叉堆优化的dijkstra求“1”到各点的最短路长度d【N】;
然后:
怎么求出到达某点的这样的路径有多少条呢
?我们只要遍历一遍某点前面的点们,看看有没有符
合要求d【前面的点】+v(边权值)=d【“1”点到该点的最短路】的点即可。前面的点指的是与当前点
有边相连且在到达当前点之前到达的点。我们可以在求出“1”点到达每个点的最短路之后根据dis对这些
点进行排序。然后可达关系的后面的点与前面点的先后关系就是在排序后序列中的关系。(PS:遍历所有点、二层循环遍历与当前点连接的所有点就好了,他后面的点的d加上两点间边的权值肯定不会是
到达当前点的最短路,所以一定不会被选择,emm,,,,,,也就说没必要排序,可能时间复杂上稍有差异吧,
不过应该也不大)。
AC代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
#define ll long long
using namespace std;
const int N=100010,M=1000010;
int head[N];
int ver[M];
int edge[M];
int Next[M];
bool v[N];
int tot;
int d[N];
priority_queue< pair<int,int> >Q;
void add(int x,int y,int z)
{
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void dijkstra()
{
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));
d[1]=0;
Q.push(make_pair(0,1));
while(Q.size())
{
int x=Q.top().second;
Q.pop();
if(v[x])continue;
v[x]=1;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i],z=edge[i];
if(d[y]>d[x]+z)
{
d[y]=d[x]+z;
Q.push(make_pair(-d[y],y));
}
}
}
}
int num[10010];
int main()
{
int n,m;
while(cin>>n>>m)
{
tot=0;
memset(head,0,sizeof(head));
memset(ver,0,sizeof(ver));
memset(edge,0,sizeof(edge));
memset(Next,0,sizeof(Next));
for(int i=1;i<=m;++i)
{
int x,y,l;
cin>>x>>y>>l;
add(x,y,l);//dijkstra用于无向图,所以,别忘了建双向边;
add(y,x,l);
}
dijkstra();//求最短路
memset(num,0,sizeof(num));
num[1]=1;
for(int i=2;i<=n;++i)//求到达某点路径中长度为最短路的路径数目;
{
for(int j=head[i];j;j=Next[j])
{
int pp=ver[j],vv=edge[j];//邻接表常规操作
if(d[i]==d[pp]+vv)num[i]++;
}
}
ll ans=1;
for(int i=1;i<=n;++i)
{
ans=ans*num[i]%2147483647;//叠乘答案;
}
cout<<ans<<endl;
}
}
The end;