题目 1492: 蓝桥杯算法提高VIP-产生数

题目

给出一个整数 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的范围,因此,可以用两种方法解决:

  1. 把结果放入char数组,进行大数乘法,但代码较复杂;
  2. 当结果是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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值