NOIp2002普及组解题报告(三)
   

                            湖南 黄艺海


题三: 产生数

[问题描述]:

  给出一个整数n(n<10^30)和k个变换规则(k<=15)。

  规则:
    1个数字可以变换成另一个数字
    规则的右部不能为零。

  问题:
    给出一个整数n和k个规则

  求出:
    经过任意次的变换(0次或多次),能产生出多少个不同的整数。

[问题分析]:

  认真分析题目之后发现,本题搜索显然是不行的,而且对于只需计数而不需求具体方案的题目,一般都不会用搜索解决,其实本题不难看出,可以用乘法原理直接进行计数,用Fi表示数字i包括本身可以变成的数字总个数(这里的变成可以是直接变成也可以是间接变成,比如3->5,5->7,那么3->7),那么对于一个数a(用数组存,长度为n),根据乘法原理它能产生出F[a[1]]*F[a[2]]*F[a[3]]*…F[a[n]]个不同整数,相信这一点大家不难理解。那么现在的关键就是如何求Fi,由于这些变换规则都是反应的数字与数字之间的关系,这很容易让我们想到用图来表示这种关系:

  1: 建立一个有向图G,初始化g[i, j]← False
  2: 如果数字i能直接变成数字j,那么g[i, j]← True

  容易知如果数字i能变成数字j,那么i到j必须存在路径,否则i是不可能变成j的,这样一来,Fi的求解就显得非常简单了,求一个顶点v包括本身能到达的顶点数的方法相当多,可以用BFS,DFS,Dijkstra,Floyd,这里介绍一种类似Floyd的有向图的传递闭包算法,该算法实现简单 ,在解决这类问题时比Floyd效率更高,所谓有向图的传递闭包就是指可达性矩阵A=[a[i, j]],其中

  a[i, j] = True 从i到j存在通路
  a[i, j] = False 从i到j不存在通路

  所以有向图传递闭包算法只需将floyd算法中的算术运算符操作'+'用相应的逻辑运算符'and'和'or'代替就可以了,其算法如下:

  for k ← 1 to n do
  for i ← 1 to n do
  for j ← 1 to n do
  a[i, j] = a[i, j] or (a[i, k] and a[k, j])

  最后值得注意的是当n很大时输出可能会超过Comp类型的范围,所以要使用高精度乘法,由于高精度算法是信息学竞赛中的基础,这里就不在详述。

[参考程序]

  下载


相关链接:NOIp2002普及组解题报告(一)
     NOIp2002普及组解题报告(二)
     NOIp2002普及组解题报告(三)
     NOIp2002普及组解题报告(四)


   

 
网站导航 | 关于曙光 | 联系我们 | 请提意见
Copyright © FuJian Sunshine Educational Info. Co.,Ltd.
福建曙光教育资讯有限公司 版权所有