城堡(统计最短路数问题)

29 篇文章 1 订阅

城堡

问题描述:
给定一张n个点m条边的无向连通图,每条边有边权。我们需要从m条边中
选出n−1条,构成一棵树。记原图中从 1 号点到每个节点的最短路径长度为di,树中从 1 号点到每个节点的最短路径长度为? ? ,构出的树应当满足对于任意节点si,都有di=si。
请你求出选出n−1条边的方案数。
输入格式:
输入的第一行包含两个整数n和m。
接下来m行,每行包含三个整数u、v和w,描述一条连接节点u和v且边权为
w的边。
输出格式:
输出一行,包含一个整数,代表方案数对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≤w≤100。

#include<iostream>
#include<cstdio>
#include<queue>
#define lon long long
using namespace std;
const int maxn=10010;
const long long mod=0x7fffffff;
lon n,m,tot,c[maxn],head[maxn],dis[maxn];
bool flag[maxn];
struct node
{
    lon to;
    lon from;
    lon w;
    lon next;
}e[1000010];
lon init()
{
    lon x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
void add_edge(lon u,lon v,lon w)
{
    e[++tot].to=v;
    e[tot].from=u;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot;
}
void spfa()
{
    for(lon i=1;i<=n;i++)
    dis[i]=0x7fffffff;dis[1]=0;
    queue<lon> q;
    q.push(1);flag[1]=1;
    while(!q.empty())
    {
        lon u=q.front();
        q.pop();flag[u]=0;
        for(lon i=head[u];i;i=e[i].next)
        {
            lon v=e[i].to;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!flag[v])
                {
                    q.push(v);
                    flag[v]=1;
                }
            }
        }
    }
}
int main()
{
    freopen("castle.in","r",stdin);
    freopen("castle.out","w",stdout);
    lon x,y,z;
    n=init();m=init();
    for(lon i=1;i<=m;i++)
    {
        x=init();y=init();z=init();
        add_edge(x,y,z);
        add_edge(y,x,z);
    }
    spfa();
    lon ans=1;
    for(int i=1;i<=tot;i++)
    {
        lon u=e[i].from;
        lon v=e[i].to;
        if(dis[v]==dis[u]+e[i].w)
        c[v]++;
    }
    for(int i=2;i<=n;i++)
    ans=(ans*c[i])%mod;
    cout<<ans;
    fclose(stdin);fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值