NOIP2002 产生数
Posted Kuro同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2002 产生数相关的知识,希望对你有一定的参考价值。
题目描述
给出一个整数n(n<1030) 和k个变换规则(k<=15)。
规则:
一位数可变换成另一个一位数:
规则的右部不能为零。
例如:n=234。有规则(k=2):
2->5
3->6
上面的整数234经过变换后可能产生出的整数为(包括原数):
234
534
264
564
共4种不同的产生数
问题:
给出一个整数n和k个规则。求出:
经过任意次的变换(0次或多次),能产生出多少个不同整数。仅要求输出个数。
输入格式
每个测试文件只包含一组测试数据,每组输入的第一行输入两个整数n和k(n<1030,k<=15)。
接下来k行每行输入一个规则,每个规则由两个整数构成。
输出
对于每组输入数据,输出一个整数,表示满足条件的个数。
样例输入
234 2
2 5
3 6
样例输出
4
需要考虑两点
1、一共有15种操作 说明一个数可以变成多个不同的数
如果存在 2个操作 a->b b->c 则a既可以变到b也可以变到c
所以可以通过DFS求每个数可变得其他数的个数
2、最多可能有30位数 所以最大可能9^30
需要模拟大数乘法 而每次乘数有一个 不超过10 所以并不难
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int op[10][10];
char str[105];
int vis[10];
int value[32];
int maxlen=1;
void dfs(int a) //搜索出每个数可以到达的数的个数 用SS保存
if(vis[a])
return;
vis[a]=1;
ss++;
for(int i=0;i<=9;i++)
if(op[a][i]==1)
dfs(i);
void multiple(int x) //最大可能 9^30 超long long 所有模拟大数乘法
int carry=0; //carry表示进位
for(int i=1;i<=maxlen;i++)
value[i]=value[i]*x+carry;
carry=value[i]/10;
value[i]=value[i]%10;
if(carry>0)
value[++maxlen]=carry;
return;
int main()
int m,n,i,j,k;
int s;
value[1]=1;
memset(op,0,sizeof(op));
scanf("%s%d",str,&k);
int a,b;
if(k==0)
cout<<1<<endl;
return 0;
while(k--)
scanf("%d%d",&a,&b);
op[a][b]=1; //op[a][b]代表a可以到b
int len=strlen(str);
for(i=0;i<len;i++)
memset(vis,0,sizeof(vis));
ss=0;
dfs(str[i]-'0'); //求出每位可转换数的乘积 //其实可以用一个数组保存每个数可转换的数的个数
multiple(ss);
for(i=maxlen;i>=1;i--)
cout<<value[i];
cout<<endl;
return 0;
以上是关于NOIP2002 产生数的主要内容,如果未能解决你的问题,请参考以下文章