题目链接:https://www.luogu.org/problem/P1037
题目描述
给出一个整数n(n<10 30)和 k 个变换规则(k≤15)。
规则:
一位数可变换成另一个一位数:
规则的右部不能为零。
例如n=234。有规则(k=2):
2->5
3->6
上面的整数234经过变换后可能产生出的整数为(包括原数):
234
534
264
564
共4 种不同的产生数
问题:
给出一个整数 n 和 k 个规则。
求出:
经过任意次的变换(0次或多次),能产生出多少个不同整数。
仅要求输出个数。
输入输出:略
算法
刚开始想暴力发现行不通,看到题解中说到 floyed 算法,就借机复习了一下。
考虑到可能有 2–>3–>5–>1 这种路径,所以这道题目要借用到 floyed 最短路径算法来求出各个数字之间变换交替的通路。考虑到数据范围的问题,需要使用高精度运算用以处理结果。
源码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
string str;
int vis[10][10], f[10], num[110], k;
//搜索路径
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() {
cin>>str>>k;
while(k--) {
int x, y; cin>>x>>y;
vis[x][y]=true;
}
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<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;
}