[noip2002] 产生数


题目描述

给出一个整数 n (n<1030)个变换规则 (k < 15) 

规则:

一位数可变换成另一个一位数:

规则的右部不能为零。

例如:n = 234 。有规则( k=2 ):

2-> 5
3-> 6
上面的整数 234 经过变换后可能产生出的整数为(包括原数):

234
534
264
564

44 种不同的产生数

问题:

给出一个整数 n 和 k 个规则。

求出:

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

仅要求输出个数。

思路

floyd+高精度,用floyd求出每个数字可以变成多少种数字,根据乘法原理乘起来]

#include 
#include <string>
using namespace std;
string str;
int k,vis[10][10],f[10],num[101];
inline void floyd() {    //弗洛伊德
    for (int k = 0;k <= 9;k++)
        for (int i = 0;i <= 9;i++)
            for (int j = 0;j <= 9;j++) vis[i][j] = vis[i][j] || (vis[i][k] && vis[k][j]);
}
int main (){
    ios::sync_with_stdio(false);
    cin >> str >> k;
    while (k--) {
        int a,b;
        cin >> a >> b;
        vis[a][b] = true;    //a可以变成b
    }
    for (int i = 0;i <= 9;i++) vis[i][i] = true;    //自己可以变成自己
    floyd();
    for (int i = 0;i <= 9;i++)
        for (int j = 0;j <= 9;j++)
            if (vis[i][j]) f[i]++;    //求出i可以变成多少种数字
    int len = 2; num[1] = 1;
    for (int i = 0;i < (int)str.length();i++) {    //高精度
        for (int j = 1;j <= 100;j++) num[j] *= f[str[i]-'0'];
        for (int j = 1;j <= 100;j++)
            if (num[j] >= 10) {    //进位
                num[j+1] += num[j]/10;
                num[j] %= 10;
            }
        while (num[len]) len++;    //求出长度
    }
    for (int i = len-1;i >= 1;i--) cout << num[i];    //输出
    return 0;
}