LOJ10064黑暗城堡

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

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

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

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

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

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

输入格式
第一行为两个由空格隔开的整数 N, M;

第二行到第 M+1 行为 3 个由空格隔开的整数 x, y, l:表示 x 号房间与 y 号房间之间的通道长度为 l。

输出格式
一个整数:不同的城堡修建方案数对 2^{31} -1 取模之后的结果。

样例
样例输入
4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1
样例输出
6
样例说明
一共有 4 个房间,6 条道路,其中 1 号和 2 号,1 号和 3 号,1 号和 4 号,2 号和 3 号,2 号和 4 号,3 号和 4 号房间之间的通道长度分别为 1,2,3,1,2,1。

而不同的城堡修建方案数对 2^{31} -1 取模之后的结果为 6。

数据范围与提示
对于全部数据,1≤N≤1000,1≤M≤N(N−1)/2​,1≤l≤200。

——————————————————————————————————————————

这是一道很神的题。

首先dij,求出1号点到其他点的最短距离。

然后扫描所有边,如果dis[v]==dis[u]+e[i].w,说明让v点的距离为给最短距离的路径又多了一条,所以,cnt[v]++;

最终结果就是所有点的cnt[]相乘。

!!!!!!!!!!!!

。。。。。。。。。。。。。。。

——————————————————————————————————————————

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long mod=((long long)1<<31)-1;
 4 const int maxn=1010;
 5 const int maxm=5e5;
 6 int n,m;
 7 struct edge
 8 {
 9     int u,v,w,nxt;
10 }e[maxm<<1];
11 int head[maxn],js;
12 void addage(int u,int v,int w)
13 {
14     e[++js].u=u;e[js].v=v;e[js].w=w;
15     e[js].nxt=head[u];head[u]=js;
16 }
17 int dis[maxn];
18 bool vis[maxn];
19 struct node
20 {
21     int dis,p;
22     bool operator < (node b)const
23     {
24         return dis>b.dis;
25     }
26 };
27 priority_queue< node > q;
28 void dij()
29 {
30     memset(dis,0x7f,sizeof(dis));
31     dis[1]=0;
32     q.push((node){0,1});
33     while(!q.empty())
34     {
35         node tp=q.top();
36         q.pop();
37         int u=tp.p;
38         if(vis[u])continue;
39         vis[u]=1;
40         for(int i=head[u];i;i=e[i].nxt)
41         {
42             int v=e[i].v;
43             if(dis[u]+e[i].w<dis[v])
44             {
45                 dis[v]=dis[u]+e[i].w;
46                 q.push((node){dis[v],v});
47             }
48         }
49     }        
50 }
51 int cnt[maxn];
52 long long ans=1;
53 int main()
54 {
55     scanf("%d%d",&n,&m);
56     for(int u,v,w,i=0;i<m;++i)
57     {
58         scanf("%d%d%d",&u,&v,&w);
59         addage(u,v,w);addage(v,u,w);
60     }
61     dij();
62     for(int j=1;j<=n;++j)
63         for(int i=head[j];i;i=e[i].nxt)
64             if(dis[e[i].v]==dis[e[i].u]+e[i].w)cnt[e[i].v]++;
65         for(int i=2;i<=n;++i)ans=ans*cnt[i]%mod;
66     cout<<ans;
67     return 0;
68 }
View Code

 

转载于:https://www.cnblogs.com/gryzy/p/10481998.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值