首页 > 其他分享 >UVA12107 题解

UVA12107 题解

时间:2023-03-11 20:56:34浏览次数:54  
标签:cnt return int 题解 modify pos len UVA12107

前言

题目传送门!

更好的阅读体验?

很久以前的一道搜索大模拟题目,另一篇题解的写法有点鬼畜,所以就来补篇题解。

题面

给你一个数字谜。修改最少次数(每次修改一个数位为空格或者数字)使得数字谜只有唯一解。

求出修改方案,字典序最小(假设空格字典序小于数字)。注意数不能含有前导零。

样例解释的话可以看图片。

思路

首先很明显是迭代加深搜索。枚举修改次数并依次检验。

首先当然是要学会判断数字谜是否成立了!这个是一个类似高精度的处理。

挂掉的情况有三种:位数不对、有前导零、数字不对。

bool calc() //当前等式是否能成立(最后一个数可能有空格)
{
	int x = toint(a[1]), y = toint(a[2]), z = x * y;
	string t = ""; //将 z 转化为 string 类型
	for (int i = 0; i < len[3]; i++) t += (char)(z % 10 + '0'), z /= 10;
	reverse(t.begin(), t.end());
	if (z != 0 || t[0] == '0') return false; //位数不对就挂掉
	for (int i = 0; i < len[3]; i++)
		if (a[3][i] != '*' && a[3][i] != t[i]) //不是空格,但和目标不同,挂掉
			return false;
	return true;
}

上述代码中,\(\operatorname{toint}(s)\) 表示将字符串 \(s\) 转成整数。

然后是搜索主体,搜的过程中维护几个数据:

  • \(\texttt{c}\) 表示当前是第几个数。\(a \times b = c\) 中,\(a, b, c\) 依次是第 \(1, 2, 3\) 个数。
  • \(\texttt{pos}\) 表示当前是这个数的第几个数位。
  • \(\texttt{modify}\) 表示修改的次数。

每次往下一个字符跳。注意,不能把首位修改成 \(0\)。

bool dfs(int modify, int c, int pos) //modify:修改了多少次 c:当前位置
{
	if (modify == dep) return chk(1, 0) == 1; //不能再改了,看看能不能满足
	if (c == 4) return false;
	int nxtc = (pos == len[c]-1 ? c+1 : c), nxtpos = (pos == len[c]-1 ? 0 : pos+1); //求下一位
	for (int i = 0; i <= 10; i++)
	{
		if (i == 1 && pos == 0) continue; //首位不能为0
		if (a[c][pos] == dict[i])
		{
			if (dfs(modify, nxtc, nxtpos)) return true; //不用改,modify 不变
		}
		else
		{
			char zltAKIOI = a[c][pos]; //神仙祈福
			a[c][pos] = dict[i];
			if (dfs(modify+1, nxtc, nxtpos)) return true; //要改,modify 加一
			a[c][pos] = zltAKIOI; //神仙附身
		}
	}
	return false;
}

最后就是 \(\operatorname{check}()\) 来检验数字谜是否有唯一解。

大体与搜索主体相同的,注意一下搜完之后复原就行了。

代码

一年前的代码了捏,凑合着看看。注释以前写的。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
void fastio()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
}
string a[5];
char dict[15] = {'*', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; //字典序排列
int len[5], dep;
int toint(string s) //将字符串转为数
{
	int x = 0, len = s.length();
	for (int i = 0; i < len; i++) x = (x * 10) + (s[i] - '0');
	return x;
}
bool calc() //当前等式是否能成立(最后一个数可能有空格)
{
	int x = toint(a[1]), y = toint(a[2]), z = x * y;
	string t = ""; //将 z 转化为 string 类型
	for (int i = 0; i < len[3]; i++) t += (char)(z % 10 + '0'), z /= 10;
	reverse(t.begin(), t.end());
	if (z != 0 || t[0] == '0') return false; //位数不对就挂掉
	for (int i = 0; i < len[3]; i++)
		if (a[3][i] != '*' && a[3][i] != t[i]) //不是空格,但和目标不同,挂掉
			return false;
	return true;
}
int chk(int c, int pos) //看看是否唯一解
{
	int cnt = 0; //记录有多少个解
	if (c == 3) return calc(); //前两个数填完了
	int nxtc = (pos == len[c]-1 ? c+1 : c), nxtpos = (pos == len[c]-1 ? 0 : pos+1); //求下一位
	if (a[c][pos] == '*') //乱填一下
	{
		for (int i = 1; i <= 10; i++) //不能填空格
		{
			if (i == 1 && pos == 0) continue; //首位不能为0
			a[c][pos] = dict[i], cnt += chk(nxtc, nxtpos);
			if (cnt > 1) break; //反正都不是唯一解了,直接退出就行。
		}
		a[c][pos] = '*'; //恢复
	}
	else cnt = chk(nxtc, nxtpos); //有数字就不用乱填了
	return cnt; //此时,cnt=0 无解;cnt=1 唯一解;cnt>=2 多解。注意 cnt>=2 时不一定是真正解的数量 
}
bool dfs(int modify, int c, int pos) //modify:修改了多少次 c:当前位置
{
	if (modify == dep) return chk(1, 0) == 1; //不能再改了,看看能不能满足
	if (c == 4) return false;
	int nxtc = (pos == len[c]-1 ? c+1 : c), nxtpos = (pos == len[c]-1 ? 0 : pos+1); //求下一位
	for (int i = 0; i <= 10; i++)
	{
		if (i == 1 && pos == 0) continue; //首位不能为0
		if (a[c][pos] == dict[i])
		{
			if (dfs(modify, nxtc, nxtpos)) return true; //不用改,modify 不变
		}
		else
		{
			char zltAKIOI = a[c][pos]; //神仙祈福
			a[c][pos] = dict[i];
			if (dfs(modify+1, nxtc, nxtpos)) return true; //要改,modify 加一
			a[c][pos] = zltAKIOI; //神仙附身
		}
	}
	return false;
}
int main()
{
	fastio();
	for (int i = 1;; i++) 
	{
		cin >> a[1];
		if (a[1] == "0") break;
		cin >> a[2] >> a[3];
		len[1] = a[1].length(), len[2] = a[2].length(), len[3] = a[3].length();
		for (dep = 0;; dep++) //迭代加深搜索 
			if (dfs(0, 1, 0))
			{
				cout << "Case " << i << ": " << a[1] << ' ' << a[2] << ' ' << a[3] << '\n';
				break;
			}		
	}
	return 0;
}

希望能帮助到大家!

标签:cnt,return,int,题解,modify,pos,len,UVA12107
From: https://www.cnblogs.com/liangbowen/p/17206903.html

相关文章

  • [POI2001][HAOI2007] 反素数 题解
    前置知识:一些关于约数的小常识。唯一分解定理对于所有正整数\(n\),一定有唯一分解方式\(n=p_1^{c_1}p_2^{c_2}\cdotsp_m^{c_m}\),其中\(p_1<p_2<\cdots<p_m\),......
  • P3530[POI2012 FES-Festival] 题解
    题面链接简要题意对于数列\(\{v_n\}\),有两种约束\(v_i=v_j+1\)和\(v_i\gev_j\),问\(\{v_n\}\)最多有多少个不同的项。解法考虑先建图,注意到如果约束图是DAG,那么......
  • CF1795 G.Removal Sequences - 题解
    记\(N(u)\)表示图上与点\(u\)相邻的点,\(p_u=deg_u-a_u\),其中\(deg_u\)为无向图上点\(u\)的度数。首先要删除\(p_u=0\)的点,同时\(\forallv\inN(u),p_v......
  • CF888D Almost Identity Permutations 题解
    CF链接:AlmostIdentityPermutationsLuogu链接:AlmostIdentityPermutations${\scr\color{Aquamarine}{\text{Solution}}}$前言这好像是一道能用数学秒掉的题目但......
  • 「THUPC 2023 初赛」欺诈游戏 题解
    写点无脑做法。设走私者的策略是\(p_i\)概率选\(i\),检查官的策略是\(q_i\)概率选\(i\)。因为两者策略均最优,所以走私者选任意一个数得到的期望收益相同,检查官选任......
  • CF1802D题解
    CF1802D题解传送门更好的阅读体验简化题意:有n个商店,每个商店卖a,b两种商品,价格分别为\(a_i,b_i\),你需要在每个商店买一个商品,并且不能在所有商店都买同一种商品,最......
  • Python - Crypto 导入失败问题解决记录
    python3.7Mac安装psycopg2$pipinstallpsycopg2...Error:pg_configexecutablenotfound....出现报错:Error:pg_configexecutablenotfound.解决参考:h......
  • P5752 [NOI1999] 棋盘分割题解
    本文来自我的洛谷博客。本题解力求使用清晰易懂的图片和文字,讲解最简洁的道理。请大家耐心地看完,注意要结合图片一起哦~~2022-8-24更改了格式与错别字2022-8-28更改......
  • python工具jupyternotebook页面打开空白问题解决方法
    jupyternotebook页面打开空白问题解决方法下载anaconda自带的jupyternotebook找到这个配置文件C:\Users\Administrator.jupyter\jupyter_notebook_config.py打开找......
  • P7712 [Ynoi2077] hlcpq 题解
    虚式优化建图题。首先有一个很显然的暴力,对于两条相交的线段连一条边,然后跑割点。这个暴力的问题在于边与点的时间复杂度相差过大,无论是空间还是时间都无法承受,所以可以......