树的计数

题目:

1.树的计数

【问题描述】

图和树有很密切的关系。某一天牙神产生了一个很奇怪的想法:删去一些边把一个无向图变成一个树,也就是将边留下 N − 1 条。而且对于任意一个点 i,要保证现在树中的边满足 1 号点到 i 号点的路径长度等于原图中 1 号点到 i 号点的最短路长度。牙神请你帮忙数一下有多少个目标树满足要求。答案对1000000007 取模。

【输入格式】

第一行,一个整数N。接下来 N 行每行 N 个数,第 i 行第 j 个数表示 i 和 j 的连边关系,0 表示没有边。

【输出格式】

一个整数,表示答案。

【输入样例】

3

0 2 1

2 0 1

1 1 0

【输出样例】

2

【数据规模】

对于 40%数据 N ≤  50

对于 100%数据 N ≤  1000,每条边边权在[0,14]内。

 

题解:按照最短路径的思想,记录每一个点被假如已选集合的时候,有几个点可以更新这个点的最短路径。

按照乘法原理,最后答案就是每一个点的有几个点可以更新这个点的最短路径相乘

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1005,M=1000000007;
int n,a[N][N],dis[N],g[N],f[N];
int main()
{
    freopen("treecnt.in","r",stdin);
    freopen("treecnt.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)scanf("%d",&a[i][j]);
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
      if (!a[i][j])a[i][j]=10000005; 
    for (int i=1;i<=n;i++)dis[i]=a[1][i];
    for (int i=1;i<=n;i++)g[i]=1;
    long long ans=1;
    f[1]=1;
    for (int i=1;i<n;i++)
     {
         int l=-1;
         for (int j=1;j<=n;j++)
          if (!f[j]&&(l==-1||dis[l]>dis[j]))l=j;
         f[l]=1;
        (ans*=g[l])%=M;
        for (int j=1;j<=n;j++)
         if (!f[j])
          {
              if (dis[j]>dis[l]+a[l][j])
             dis[j]=dis[l]+a[l][j],g[j]=0;
            if (dis[j]==dis[l]+a[l][j])g[j]++;
          }       
     }
    printf("%lld",ans); 
}

 

转载于:https://www.cnblogs.com/xuanyiming/p/7506518.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值