题目:http://codevs.cn/problem/1009/
思路:计算每个数字的可能值,然后按位将所有可能相乘,得到可能所有可能数。
题解:
/* 1009 产生数 */
#include <stdio.h>
#include <stdlib.h>
#define DEBUG
#define MAX 10
#define MAXN 32 /* 整数最长长度 */
#define MAXR 15 /* 变换规则最大数 */
#define toint(X) X-'0' /* 字符转整型 */
/* 变换规则结构体 */
struct _rule{
int x;
int y;
}rules[MAXR]; /* 所有变换规则 */
char n[MAXN]; /* 基数 */
int length; /* 基数长度 */
int k; /* 变换规则数,选择变换规则数 */
long long count; /* 产生数计数 */
int weight[MAX]; /* 每位的权值 */
int set[MAX]; /* 并查集,用于计算每位的可能值 */
/* 初始化并查集 */
void init_set(){
int i;
for(i = 0; i < MAX; i++){
set[i] = i;
}
}
/* 主函数入口 */
int main(int argc, char *argv[]) {
int i, x, y;
#ifdef DEBUG
FILE *fp;
if(NULL == (fp = fopen("data.txt", "r"))){
return 1;
}
#endif
/* 获取基数和变换规则数 */
#ifdef DEBUG
fscanf(fp, "%s %d", n, &k);
#else
scanf("%s %d", n, &k);
#endif
/* 获取变换规则 */
for(i = 0; i < k; i++){
#ifdef DEBUG
fscanf(fp, "%d %d", &x, &y);
#else
scanf("%d %d", &x, &y);
#endif
rules[i].x = x;
rules[i].y = y;
}
/* 计算基数长度 */
length = 0;
while('\0' != n[length]){
length++;
}
/* 初始化每位的权值 */
for(i = 0; i < MAX; i++){
weight[i] = 0;
}
for(x = 0; x < k; x++){
init_set();
set[rules[x].y] = rules[x].x;
/* 已计算,跳过本次循环 */
if(weight[rules[x].x] > 0){
continue;
}
/* 前向搜索 */
for(y = 0; y < k; y++){
if(set[rules[y].x] == rules[x].x){
set[rules[y].y] = rules[x].x;
}
}
/* 逆向搜索 */
for(y = k - 1; y >= 0; y--){
if(set[rules[y].x] == rules[x].x){
set[rules[y].y] = rules[x].x;
}
}
/* 计算权值 */
for(y = 0; y < MAX; y++){
if(set[y] == rules[x].x){
weight[set[y]]++;
}
}
}
/* 计算所有可能值, 权值相乘 */
count = 1;
for(i = 0; i < length; i++){
if(weight[toint(n[i])] > 0){
count = count * weight[toint(n[i])] ;
}
}
printf("%lld", count);
#ifdef DEBUG
fclose(fp);
#endif
return 0;
}