题目

digit puzzle 数字谜 Uva12107
给一个不完整表达式,要求修改尽量少的数,使修改后的数字谜只有唯一解。空格和数字可以随意替换,但不能增删,表达式中所有涉及的数必须是没有前导零的正数。输入数字谜一定形如a*b=c,其中a、b、c分别最多有2、2、4位。用下划线表示未知数字。输入保证会有解,即有经过变换后肯定能有一个表达式有唯一解。如果有多个解,输出字典序最小的解, 下划线比数字小

 输入 _*__=78 //表达式 答案不唯一 1*78=78 2*39=78输出_*_7=_8 //表达式唯一解 4*17=68; 右原始表达式第3个下划线和7交换1次得到
tip:7*__=_8 //表达式也有唯一解 7*14=98; 但修改次数也是1 但字典序不是最小

思路

初始状态S
while True:每次交换一个不同的数字或下划线 形成新的表达式Sif 表达式S 有唯一解:停止搜索,结束

1、首先要有一个逻辑 判断表达式解是否唯一
2、每次交换一个不同的数字或下划线 形成新的表达式,校验是否唯一解,不唯一重复步骤2

问题

1、如何保证修改次数最小?
IDA*深度迭代搜索
2、如何保证修改次数相同时 字典序最小?
在搜索时保证首先搜索字典序最小的状态,那么第一个搜索到的解就是答案
3、如何判断表达式解是否唯一?

初始状态S
all=0
def isOk(S):if S 中没有空格:if 校验表达式==成立:all++;else for 下划线 in 所有的下换线:替换下划线 = 0,1,2,...,9 获得新的状态S1。递归S1
#上述思路 可以优化,不过下面代码没有实现
# 1\ 替换a、b中的下换线。计算c=a*b, 匹配c与表达式中c
# 2\ 一旦all >=2后 就不需要查找了。肯定不是唯一解

4、如何存储表达式 (这是任何题目都避免不了的问题)
因为最多涉及8个数字或下划线 ,用4个bit存储一个数字, 正好用1个int型=32位;
因为下划线比数字小,所以空格用0=0000表示 数字用原始数字+1存储即[0001, 1010] 不存在用NAN=15=1111表示。如果数字是无符号的int型,那么数字越小对应的字典序也越小

案例验证

输入 _*__=78
输出 _*_7=_8

代码

/** 思路* 最多涉及8个数字 用4个bit存储一个数字, 正好32位=1个int型; 空格用0=0000表示 数字用原始数字+1存储即[0001, 1010] 不存在用NAN=15=1111表示,一定是数无符号整型* 初始状态s0* 转移方程 s = { sj | si中8个数字或空格, 除15外 任意两个不同的值交换得到sj }**/#define MAXDEPTH 10
#define NAN 15// 交换s[i]<-->s[j]
#define chg(s, i, j)\
do{\int __i, __j, __k;\for( __i=(i)*4, __j=(j)*4, __k=0; __k<4; __k++, __i++, __j++)\{\if ( (s&1<<__i)>>__i != (s&1<<__j)>>__j )\{\if ( s&1<<__i ) { s &= ~(1<<__i);  s |= (1<<__j); }\else     { s &= ~(1<<__j);  s |= (1<<__i); }\}\}\
}while(0)//获取s[i]的数字
#define slice(s, i) (s>>(i)*4&15)//更新s[i]的数字=v
#define update(s, i, v) do{ s &= ~(15<<(i)*4); s |= (v)<<(i)*4; } while(0)int MaxDepth;
int depth;
int ans;static int okNum(int s, int index)
{int i, k, v, a, b, c, num;num = 0;// 所有空格替换完毕if (index==-1){// 解析a,b,ca=b=c=0;for(i=0; i<8; i++){// 跳过NANif(  slice(s,i) == NAN ) continue;if(i==0) {c += (slice(s,i)-1);}else if(i==1) {c += (slice(s,i)-1) * 10;}else if(i==2) {c += (slice(s,i)-1) * 100;}else if(i==3) {c += (slice(s,i)-1) * 1000;}else if(i==4) {b += (slice(s,i)-1);}else if(i==5) {b += (slice(s,i)-1) * 10;}else if(i==6) {a += (slice(s,i)-1);}else if(i==7) {a += (slice(s,i)-1) * 10;}}return a*b==c ? 1:0 ;}/** 遇到空格0 时填充数字1,2,...,10, 保证没有前导0* 递归到index-1*/if(  slice(s,index) == 0 ){for(v=0; v<10; v++){// 1、index=3 5 7时 不能为0.// 2、前一个index+1=1(值为0)或NAN(不存在)时 不能为0if(v==0){if( index==3 || index==5 || index==7) continue;if( slice(s,index+1)==1 || slice(s,index+1)==NAN) continue;}update(s, index, v+1);num += okNum(s, index-1);}}else{num += okNum(s, index-1);}return num;
}/* 搜索第一个符合条件的答案 */
static int search(int s)
{int i,j, g, v, a, b, k;unsigned int tmp, sNew[28]; // 数量<=8时 任意交换两个最多7*8/2=28种可能if (depth >= MaxDepth ) return 0;if( okNum(s, 7)==1 ){ans = s;return 1;}// 初始化sNew 在有序集合{s|交换s中任意两个不相同的数字或空格, si<sj }g=-1;for(i=0; i<8; i++) if( slice(s, i)!=NAN ){for(j=i+1; j<8; j++) if( slice(s, j)!=NAN ){if(slice(s, i)==slice(s, j)) continue;tmp = s;chg(tmp, i, j);k=g;while(k>=0 && sNew[k] > tmp) {sNew[k+1]=sNew[k];k--;}sNew[k+1]=tmp;g++;}}// 寻找需要交换的a, b 使得交换后 中最小k小// 按照交换后字典序 曾序递归for(i=0; i<=g; i++){depth++;if ( search(sNew[i]) ) return 1;depth--;}return 0;
}int main()
{int i,j,k,l, n, s0;char text[8+1];scanf("%s", text);//初始化答案ans=-1;// 初始化s0l=-1;while(text[++l]!='\0');s0=-1;k=0;for(i=0,j=l-1; j>=0; j--){if( text[j] == '=' ) i = 4;else if( text[j] == '*') i = 6;else{update(s0, i, (text[j]=='_'?0:(text[j]-'0')+1));i++;}}// printf("s0:");// ppp(&s0, 32);// IDA*搜索for(MaxDepth=1; MaxDepth<MAXDEPTH;  MaxDepth++)if( search(s0) ) break;// 打印答案// printf("ans:");// ppp(&s0, 32);if( ans==-1 ) printf("no solution\n");else{for(i=7; i>=0; i--){if(i==5) printf("*");if(i==3) printf("=");j = slice(ans, i);if(j==0) printf("_");else if(j!=NAN) printf("%d", j-1);}printf("\n");}return 0;
}

digit puzzle 数字谜 Uva12107相关推荐

  1. 紫书搜索 习题7-8 UVA - 12107 Digit Puzzle IDA*迭代加深搜索

    题目链接: https://vjudge.net/problem/UVA-12107 题意: 给出一个数字谜,要求修改尽量少的数,使修改后的数字谜只有唯一解.空格和数字可以随意替换,但不能增删,数字谜 ...

  2. 数字谜1 C实现

    该问题出自<C语言名题精选百则技巧篇> 在一些游戏与休闲的书中,经常看到如下的字谜: VINGT CINQ +      CINQ TRENTE 写一个程序进行破解. 说明: 数字谜的规则 ...

  3. 进位位判别法_竖式数字谜五位判别法分别是哪些

    "算式谜"一般是指那些含有未知数数字或缺少运算符号的算式.解决这类问题可以根据已学过的知识,运用正确的分析推理方法,确定算式中未知数和运算符号.解答问题时,要想仔细审题,分析数字之 ...

  4. UVA12107Digit Puzzle数字字谜(迭代加深搜索)

    题意:给你一个字谜,让你改最少的数,使等式有唯一解. 分析:两次dfs,一次枚举改动,一次枚举所有解,判断是否有且仅有一个解. #include<cstdio> #include<c ...

  5. c语言穷举法等式求缺位数,四年级下册数学奥数试题-培优拓展训练--第13讲:数字谜题(教师版)...

    第十三讲数字谜题 ------------------------------------------------------------------------------------------- ...

  6. 《算法竞赛入门经典(第2版)》——学习记录

    前言:   这里主要记录本人在学习紫书过程中充分理解过的题目的AC代码,便于以后回顾时查找代码和思路,毕竟看别人的真的有点难懂.此外,本书甚至是本书之外的相关知识学习也可能在此留下记录.   作为一只 ...

  7. C语言名题精选百则——数字问题

    C语言名题精选百则--数字问题 尊重他人的劳动,支持原创 这篇博文,D.S.Qiu将对<C语言名题精选百则>第二章进行整理推出,本章一共16个问题,不光只是书上的名题,还会依据互联网的资源 ...

  8. [2017BUAA软工]结对项目:数独扩展

    结对项目:数独扩展 1. Github项目地址 https://github.com/Slontia/Sudoku2 2. PSP估计表格 3. 关于Information Hiding, Inter ...

  9. 第二十章 : 正则表达式

    正则表达式 In the next few chapters, we are going to look at tools used to manipulate text. As wehave see ...

最新文章

  1. WEB免费打印控件推荐
  2. 模拟 Codeforces Round #249 (Div. 2) C. Cardiogram
  3. group by 和 having(转载)
  4. AWS自动化合规slide
  5. FreeRTOS 之五 动态内存管理(heap_1.c)详解
  6. leetcode 712. Minimum ASCII Delete Sum for Two Strings | 712. 两个字符串的最小ASCII删除和(暴力递归->傻缓存->DP)
  7. OpenOffice介绍
  8. vim学习日志(5):vim下wimrc的配置,解决中文乱码问题
  9. web开发者工具,261页前端面试题宝典,通用流行框架大全
  10. [转]计算机视觉之跟踪算法——相关滤波器Correlation Filter
  11. ios 7.1企业证书无线安装
  12. ADO.NET 对象模型
  13. 提醒:使用过期Win10预览版后果很严重
  14. 差异表达基因变化倍数_差异表达基因
  15. zabbix配置拓扑图标签及链路流量
  16. Win11电脑速度慢、延迟高怎么办?
  17. ubuntu 使用代理服务器 squid
  18. 苏宁618公布8大福利 5亿膨胀红包已到位
  19. STM32晶振 选型
  20. QGIS软件安装和汉化

热门文章

  1. 4-Openwrt ipv6之NAT6
  2. iOS经典讲解之清除缓存文件
  3. 从KB到GB,内存条所经过的7个历程
  4. nightwatch系列教程01——Hello Nightwatch
  5. unity愤怒的小鸟学习制作(一)
  6. 01背包输出路径、完全背包、多重背包
  7. 水银导电滑环的应用领域和安装注意事项
  8. Linux操作系统-文件(2)
  9. python自动化运维学习
  10. 【U3D小游戏】愤怒的小鸟(六)小特效