高精度生成数问题
题目描述
给出一个整数 n(n<10^30)和 k 个变换规则(k≤15)。
规则:
- 一位数可变换成另一个一位数。
- 规则的右部不能为零。
例如:n*=234。有规则(k=2):
- 2->5
- 3->6
上面的整数 234 经过变换后可能产生出的整数为(包括原数):
- 234
- 534
- 264
- 564
共 4 种不同的产生数。
现在给出一个整数 n和 k个规则。求出经过任意次的变换(0次或多次),能产生出多少个不同整数。
仅要求输出个数。
输入格式
第一行两个整数 n,k。
接下来 k行,每行两个整数 x_i,y_i。
输出格式
输出能生成的数字个数。
输入输出样例
输入 #1
234 2
2 5
3 6
输出 #1
4
解题思路
要求出经过变换可以产生多少数,其实就是求每一位数可以变换成多少数(包括自己)的乘积
要注意,转换规则具有传导性,比如两条规则2->3,3->5,那么可以得到2->5
这道题的n可以非常大,所以需要用高精度乘法,也就是模拟手算列竖式的方式,算每一位,然后再进行进位
具体步骤看代码注释
完整代码
#include <iostream>
#include <string>
using namespace std;
bool a[30][30];//a[i][j]表示数字 i可以变成 j
int k;
string n;
int f[10];//每个数字可以变成多少个数字(包括自己)
int num[30];//生成的数字个数
int reslen=1;//结果的长度
int floyd()//判断数字 i能否变成 j
{
for(int i=0;i<=9;i++)
{
for(int j=0;j<=9;j++)
{
for(int k=0;k<=9;k++)
if((a[j][i]==1)&&(a[i][k]==1))//规则的传导性
a[j][k]=1;
}
}
}
int main()
{
cin>>n>>k;
while(k>0)
{
int i,j;
cin>>i>>j;
a[i][j]=1;
k--;
}
for(int i=0;i<=9;i++)//自己变自己
a[i][i]=1;
floyd();//判断能否改变并标记
for(int i=0;i<=9;i++)//统计每个数字可以变几个数
{
for(int j=0;j<=9;j++)
{
if(a[i][j]==1) f[i]++;
}
//cout<<f[i]<<" ";
}
//cout<<endl;
num[0]=1;
for(int i=0;i<n.length();i++)//高精度乘法,模拟手算列竖式
{for(int j=0;j<100;j++)
{
num[j]*=f[n[i]-'0'];//把字符变成整数
}
for(int j=0;j<100;j++)//进位
{
if(num[j]>=10)
{
num[j+1]+=num[j]/10;
num[j]%=10;
}
}
while(num[reslen]!=0) reslen++;//结果长度
}
for(int i=reslen-1;i>=0;i--)
cout<<num[i];
return 0;
}