产生数
题目描述
给出一个整数n(n<=2000)和k个变换规则(k≤15)。规则:
①1个数字可以变换成另1个数字;
②规则中,右边的数字不能为零。(然并卵)
例如:n=234,k=2规则为
2 → 5
3 → 6
上面的整数234经过变换后可能产生出的整数为(包括原数)234,534,264,564共4种不同的产生数。
求经过任意次的变换(0次或多次),能产生出多少个不同的整数。仅要求输出不同整数个数。
输入
输入格式如下:
n
k
x1 y1
x2 y2
… …
xn yn
输出
输出一个整数为满足条件的整数个数。
样例输入
234
2
2 5
3 6
样例输出
4
数据范围限制 n<=2000;k<=15
做题地址:CCF中学生程序设计在线评测系统(需要注册)
此题初看简单,实则简单。(虽然做了一上午)
简单分析题目数据可得:
同一个数字可以对应不同变换(小心被坑)
真·暴力广搜
(但是需要判断重复)
做题步骤分析
一:基本变量
1:输入数据(俩int)
2:计数器(举栗:tot)
3:判重数组(范围要>9999)
4: 方案数组(推荐二维)
5:辅助char数组(变换用)
6:记录数队列(头文件:#include< queue >)
7:……
二:程序框架
int main()(主程序框架)
1:读入数与规则数
2:for循环读入规则
3:队列初始化
4:广搜
5:输出
6:return
void bfs()(广搜框架)
1:while(判空)
2:取数,初始化
3:for或while循环规则
4:for对每个数位操作
5:判重,入队
6:出队
另附代码一份(带注释)
#include<cstdio>
#include<algorithm>
#include<queue>//队列头文件
#include<cstring>
using namespace std;
queue<int>X;//保存可以变换的数
char s[5];//变换的临时中介
int M[10000]/*记录变过的*/,N[20][2]/*方案记录*/;
int n,k,i/*方案节点*/,tot/*记录*/,len;
void CSN(int j)//对单个位数据进行变换
{
int b;
b=s[j]-'0';
if(b==N[i][0])
s[j]=N[i][1]+'0';
return ;
}
void bfs()
{
while(!X.empty())
{
int a=X.front(),a1=a;//初始化
i=0;
while(i!=k)//尝试方案
{
sprintf(s,"%d",a1);
len=strlen(s);
for(int j=0;j<len;j++)//对每一数位变换
{
sprintf(s,"%d",a1);//尝试每一种方案
CSN(j);
sscanf(s,"%d",&a);
if(!M[a])//记录
{
sprintf(s,"%d",a1);
M[a]=1;
tot++;
printf("%d\n",a);
X.push(a);
}
}
i++;
}
X.pop();
}
}
int main()
{
int a,b;
scanf("%d %d",&n,&k);//初始化
X.push(n);
M[n]=1;
tot++;
for(int j=0;j<k;j++)
{
scanf("%d %d",&a,&b);
N[j][0]=a;
N[j][1]=b;
}
bfs();
printf("%d",tot);
return 0;
}
/*
测评数据:
运行时间:52 ms
运行空间:692 KB
代码长度:863 bytes
*/
IN THE END
虽然作者懒,不过还是要分析一下。
有一种方法是不需要判断重复的,即用set——集合保存找到的数,其根本原因是集合会自动舍弃重复存入的元素;而暴力广搜在数据大的情况下容易超时。但是广搜的代码短并且容易懂,使用的内存较少
附上一份用set做的题解,有兴趣可以看一下:竞赛题目讲解-【Standard IO】产生数