题目
给出一个整数 n 和 k 个变换规则。
规则:
一位数可变换成另一个一位数:
规则的右部不能为零。
例如:n=234。有规则(k=2):
2-> 5
3-> 6
上面的整数 234 经过变换后可能产生出的整数为(包括原数):
234
534
264
564
共 4 种不同的产生数
问题:
给出一个整数 n 和 k 个规则。
求出:
经过任意次的变换(0次或多次),能产生出多少个不同整数。
仅要求输出个数。
输入
n k
x1 y1
x2 y2
… …
xn yn
(n< 10^30)
(k< =15)
输出
一个整数(满足条件的个数)
样例输入
234 2
2 5
3 6
样例输出
4
解题思路
计算一个数能变换为多少种数,即计算每一位的数字能变换出的数字种类数之积;又为了节约运行时间,因此先利用二维的邻接矩阵,记录变化路径(如0->1,则将dp[0][1]置为1),再利用该邻接矩阵对0-9进行深度优先搜索,得到存储它们分别能变换的种类数的数组hash_change,再对读入的字符串数字进行遍历,当读入i,则乘上hash_change[i]。
难点
该题的种类数目可能会大于long int的范围,因此,可以用两种方法解决:
- 把结果放入char数组,进行大数乘法,但代码较复杂;
- 当结果是10的倍数时,记录数字末尾0的个数,并去除0;最后输出时,先输出非0部分,再补上相应个数的0。
代码
#include<stdio.h>
#include<string.h>
int dp[10][10],temp[10];
int hash_change[10];//存储每一个数字能变化到的数字个数
void DFS(int a){
int i;
for (i=0;i<10;i++)
{
if (dp[a][i]==1 && i!=a && temp[i]==0)//temp==0可以防止走回头路,陷入死循环
{
temp[i] = 1;
DFS(i);
}
}
}
int main()
{
char n[31];
int k,i,j,a,b,num_0=0;
long int num = 1;
scanf("%s %d",n,&k);
int len = strlen(n);
for (i=0;i<10;i++)//每个字符都可以变成自己
{
for (j=0;j<10;j++)
if (i==j)
dp[i][j] = 1;//自己可以变成自己
}
for (i=0;i<k;i++)//读取变换
{
scanf("%d %d",&a,&b);
if (a!=b && b!=0)//不是自己变化到自己
dp[a][b] = 1;
}
for (i=0;i<10;i++)//统计每一个数字能变化到的数字个数
{
for (j=0;j<10;j++)
temp[j] = 0;
temp[i] = 1;
DFS(i);
for (j=0;j<10;j++)//要从0开始,防止落下原来就是0的情况
hash_change[i]+=temp[j];
}
for (i=0;i<len;i++)//遍历字符
{
num*=hash_change[n[i]-48];
while (num%10==0){
num_0++;
num/=10;
}
}
printf("%ld",num);
for (i=0;i<num_0;i++)
printf("0");
return 0;
}