• 树的计数


    题目:

    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); 
    }
  • 相关阅读:
    java语言基础001
    Linux 使用硬盘
    Linux 系统运行命令 > 查看系统信息
    Linux rm 命令
    Linux 操作系统目录结构
    JavaScript || 事件基础
    My SQL随记 003 数据表基础操作语法
    My SQL随记 002 登陆
    My SQL随记 001 常用名词/结构化语言
    linux命令学习
  • 原文地址:https://www.cnblogs.com/xuanyiming/p/7506518.html
Copyright © 2020-2023  润新知