树的计数

题目:

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);
}
时间: 2024-12-13 09:42:35

树的计数的相关文章

UOJ #122 【NOI2013】 树的计数

题目链接:树的计数 这道题好神啊--正好有人讲了这道题,那么我就写掉吧-- 首先,为了方便考虑,我们可以把节点重标号,使得\(bfs\)序变成\(1,2,3,--,n\),那么显然树的深度就是\(dep_n\). 然后,我们来考虑一下\(dfs\)序和\(bfs\)序的性质.设\(dfs\)序中的第\(i\)个点为\(d_i\),那么显然有\(dep_{d_{i+1}} \le dep_{d_i}+1\).由于我们已经进行了重标号,那么通过\(bfs\)序,我们可以得到\(dep_i \le d

BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! --------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; c

UOJ#122【NOI2013】树的计数

[NOI2013]树的计数 链接:http://uoj.ac/problem/122 按BFS序来,如果$B_i$与$B_{i-1}$必须在同一层,那么贡献为0,必须在不同层那么贡献为1,都可以贡献为0.5. 因为$B_i$与$B_{i-1}$相邻,所以对方案数的改变最多+1. 必须在不同层,即$D(B_{i-1})>D(B_i)$ 都可以,$B_i$能往下移一层,不改变BFS序以及DFS序: 作为兄弟,父亲必须一样(即$D(B_{i-1})==D(B_i)-1$),不然会改变DFS序. 作为儿

BZOJ 1211: [HNOI2004]树的计数 purfer序列

1211: [HNOI2004]树的计数 Description 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi)=di的树的个数. Input 第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即树的第i个结点的度数.其中1<=n<=150,输入数据保证满足条件的树不超过10^17个. Output 输出满足条件的树有多少棵

【BZOJ】【1211】【HNOI2004】树的计数

Prufer序列+组合数学 嗯哼~给定每个点的度数!求树的种数!那么很自然的就想到是用prufer序列啦~(不知道prufer序列的……自己再找找资料吧,这里就不放了,可以去做一下BZOJ1005明明的烦恼) 那么我们令每个点的度数v[i]-1,得到每个节点在prufer序中的出现次数! 现在就是求这个prufer序有多少种了……有两种做法: 1.多重集排列数:n个元素,每种元素有a[i]个,求全排列的方案数,自己随便yy一下就可以得到$$ans=\frac{n!}{\prod (a[i]!)}

3244: [Noi2013]树的计数 - BZOJ

Description 我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序.两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同,例如下面两棵树的DFS序都是1 2 4 5 3,BFS序都是1 2 3 4 5 现给定一个DFS序和BFS序,我们想要知道,符合条件的有根树中,树的高度的平均值.即,假如共有K棵不同的有根树具有这组DFS序和BFS序,且他们的高度分别是h1,h2,...,hk,那么请你输出(h1+h2..+hk)/

【组合数学】【prufer数列】【HNOI 2004】【bzoj 1211】树的计数

1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1565 Solved: 512 Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, -, dn,编程需要输出满足d(vi)=di的树的个数. Input 第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即树

【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)

1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2468  Solved: 868 Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, -, dn,编程需要输出满足d(vi)=di的树的个数. Input 第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即

bzoj 1211 [HNOI2004]树的计数

[HNOI2004]树的计数 Description 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi)=di的树的个数. Input 第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即树的第i个结点的度数.其中1<=n<=150,输入数据保证满足条件的树不超过10^17个. Output 输出满足条件的树有多少棵. Samp