城堡

【问题描述】

给定一张n个点m条边的无向连通图,每条边有边权。我们需要从m条边中

选出n− 1条, 构成一棵树。 记原图中从 1 号点到每个节点的最短路径长度为Di ,

树中从 1 号点到每个节点的最短路径长度为Si ,构出的树应当满足对于任意节点

i都有Di= Si。请你求出选出n − 1条边的方案数。

【输入格式】

输入的第一行包含两个整数?和?。

接下来?行,每行包含三个整数?、?和?,描述一条连接节点?和?且边权为

?的边。

【输出格式】

输出一行,包含一个整数,代表方案数对2 ^31− 1取模得到的结果。

【样例输入】

3 3

1 2 2

1 3 1

2 3 1

【样例输出】

2

【数据规模和约定】

2 ≤ N ≤ 5,M ≤ 10。

对于50%的数据,满足条件的方案数不超过 10000。

对于100%的数据,2≤ N ≤ 1000,N − 1 ≤M ≤N*(N-1)/2,1 ≤ w≤ 100。

/*
  打的暴力,30分。
  其实正解似乎很好理解,但是没想到。
  因为当一张图只包含1-n的最短路径时,它一定是棵树,所以我们只要知道某个点它有多少边在最短路径中,然后用乘法原理乘起来。 
*/
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define N 1010
#define lon long long
using namespace std;
int head[N],vis[N],dis[N],n,m;lon c[N];
struct node{
    int v,pre,t;
};node e[N*N*2];
void add(int i,int x,int y,int z){
    e[i].v=y;
    e[i].t=z;
    e[i].pre=head[x];
    head[x]=i;
}
void spfa(int s){
    memset(dis,127/3,sizeof(dis));
    queue<int> q;q.push(s);
    vis[s]=1;dis[s]=0;
    while(!q.empty()){
        int u=q.front();vis[u]=0;q.pop();
        for(int i=head[u];i;i=e[i].pre){
            if(dis[e[i].v]>dis[u]+e[i].t){
                dis[e[i].v]=dis[u]+e[i].t;
                if(!vis[e[i].v]){
                    vis[e[i].v]=1;
                    q.push(e[i].v);
                }
            }
        }
    }
}
int main(){
    freopen("castle.in","r",stdin);
    freopen("castle.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        add(i*2-1,x,y,z);add(i*2,y,x,z);
    }
    spfa(1);
    queue<int> q;q.push(1);vis[1]=1;c[1]=1LL;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].pre){
            if(dis[e[i].v]==dis[u]+e[i].t){
                c[e[i].v]++;
                c[e[i].v]%=(lon)((1LL<<31LL)-1);
                if(!vis[e[i].v]){
                    q.push(e[i].v);
                    vis[e[i].v]=1;
                }
            }
        }
    }
    lon ans=1;
    for(int i=1;i<=n;i++)
        ans*=c[i],ans%=(lon)((1LL<<31LL)-1);
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/harden/p/6059943.html