POJ 3373 Changing Digits 记忆化搜索
这道题我是看了别人的题解才做出来的。题意和题解分析见原文http://blog.csdn.net/lyy289065406/article/details/6698787
这里写一下自己对题目的理解。
1. 根据k的最大范围直接搜索n最后5位的方法是错误的,因为它并不能保证所求结果为最小。因为题目要求最后结果m要尽量小,而改变n的高位能够得到更小的值。k<n的限制条件表明解必然存在,而我们搜索的最大可修改位数应该和n的位数len相等。
2. 最终结果m必须满足:最高位非0且与n位数相同 (m若等于0不视为最高位为0),m能被k整除。在此基础上,还有两个条件,它们的优先级为:m与n对应位置上的数不相等的个数尽量少 > m尽量小。即最终得到的结果不一定是最小的,但一定是与n对应位置数字不相等个数最少的。这也决定了本题dfs的写法。
3. 面对大量大数取模运算,利用mod[i][j]预处理(10^i)*j模k的值,节省了大量时间。这样在dfs的过程中,改变某一位后的m%k的值也能计算出来了。搜索时为了求得的结果最小,先从m<n开始搜,然后再搜m>n。
前者有res = (m_modk - (mod[i][n[i]] - mod[i][j]) + k) % k;
后者有res = (m_modk + (mod[i][j] - mod[i][n[i]]) + k) % k;
4. flag数组的引入是为了剪枝。如果当搜索区间为[0, pos]且此时m模k为m_modk时,如果最多修改restnum位不能成功,则修改次数少于restnum时更不可能成功,因此就不用搜索下去了。flag[pos][m_modk]始终维护上述情况无法成功的最大restnum。
我的代码
#include<stdio.h>
#include<string.h>
#define maxn 103
#define mk 10003
int len, k, n[maxn], mod[maxn][];
int m[maxn], flag[maxn][mk];
char num[maxn];
void init_mod()//mod[i][j]表示(10^i)*j模k的值
{
for (int i = ; i <= ; i++)
mod[][i] = i % k;
for (int i = ; i < len; i++)
for (int j = ; j <= ; j++)
mod[i][j] = (mod[i-][j] * ) % k;
}
int dfs(int pos,int restnum,int m_modk)
{
if (!m_modk) return ;
if (!restnum || pos < ) return ;
if (restnum <= flag[pos][m_modk]) return ;//剪枝
for (int i = pos; i > -; i--)//搜索比n小的数,要尽可能小,则从高位开始
for (int j = ; j < n[i]; j++)
{
if (i == len - && !j) continue;
int res = (m_modk - (mod[i][n[i]] - mod[i][j]) + k) % k;
m[i] = j;
if (dfs(i - , restnum - , res))
return ;
m[i] = n[i];
}
for (int i = ; i <= pos; i++)//搜索比n大的数,要尽可能小,则从低位开始
for (int j = n[i] + ; j < ; j++)
{
int res = (m_modk + (mod[i][j] - mod[i][n[i]]) + k) % k;
m[i] = j;
if (dfs(i - , restnum - , res))
return ;
m[i] = n[i];
}
flag[pos][m_modk] = restnum;//能运行到这里说明搜索失败,更新剪枝数值
return ;
}
int main()
{
while (~scanf("%s%d", num, &k))
{
int n_modk = ;
len = strlen(num);
init_mod();
for (int i = ; i < len; i++)//将num反序存入整型数组
{
n[i] = num[len--i] - '';
m[i] = n[i];
n_modk = (n_modk + mod[i][ n[i] ]) % k;//计算n % k
}
memset(flag, , sizeof(flag));
int ok = ;
for (int i = ; i <= len; i++)//从小到大枚举可以修改的位数
if (dfs(len - , i, n_modk))
break;
for (int i = len - ; i > -; i--)
printf("%d", m[i]);
printf("\n");
}
return ;
}
POJ 3373 Changing Digits 记忆化搜索的更多相关文章
- poj 3373 Changing Digits (DFS + 记忆化剪枝+鸽巢原理思想)
http://poj.org/problem?id=3373 Changing Digits Time Limit: 3000MS Memory Limit: 65536K Total Submi ...
- POJ 1088 滑雪(记忆化搜索)
滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 92384 Accepted: 34948 Description ...
- POJ 1088 滑雪 DFS 记忆化搜索
http://poj.org/problem?id=1088 校运会放假继续来水一发^ ^ 不过又要各种复习,功课拉下了许多 QAQ. 还有呀,就是昨天被一个学姐教育了一番,太感谢了,嘻嘻^ ^ 好了 ...
- POJ 1088 滑雪【记忆化搜索】
题意:给出一个二维矩阵,要求从其中的一点出发,并且当前点的值总是比下一点的值大,求最长路径 记忆化搜索,首先将d数组初始化为0,该点能够到达的路径长度保存在d数组中,同时把因为路径是非负的,所以如果已 ...
- poj 1088 滑雪_记忆化搜索
题意:略 直接用记忆化搜索就行了 #include<cstdio> #include<iostream> using namespace std; int n,m; int m ...
- POJ 3373 Changing Digits 好蛋疼的DP
一開始写的高位往低位递推,发现这样有些时候保证不了第四条要求.于是又開始写高位往低位的记忆化搜索,又发现传參什么的蛋疼的要死.然后又发现高位開始的记忆化搜索就是从低位往高位的递推呀,遂过之. dp[i ...
- POJ 3176-Cow Bowling(DP||记忆化搜索)
Cow Bowling Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14210 Accepted: 9432 Desc ...
- POJ 3373 Changing Digits
题目大意: 给出一个数n,求m,使得m的长度和n相等.能被k整除.有多个数符合条件输出与n在每位数字上改变次数最小的.改变次数同样的输出大小最小的. 共同拥有两种解法:DP解法,记忆化搜索的算法. ...
- HDU 1501 & POJ 2192 Zipper(dp记忆化搜索)
题意:给定三个串,问c串是否能由a,b串任意组合在一起组成,但注意a,b串任意组合需要保证a,b原串的顺序 例如ab,cd可组成acbd,但不能组成adcb. 分析:对字符串上的dp还是不敏感啊,虽然 ...
随机推荐
- Android开发——常见的内存泄漏以及解决方案(二)
)Android2.3以后,SoftReference不再可靠.垃圾回收期更容易回收它,不再是内存不足时才回收软引用.那么缓存机制便失去了意义.Google官方建议使用LruCache作为缓存的集合类 ...
- Monkeyrunner 录制脚本&回放
本文主要解释如何使用monkeyrunner来实现脚本的录制和回放 一:准备条件 在电脑端配置 Android SDK环境 java 环境 下载好 SDK后添加环境变量 E:\android- ...
- sql注入语句大全
sql注入语句大全--是否存在xp_cmdshell and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and n ...
- Halcon18 Linux For Armv7a 下载
Halcon18 Linux For Armv7a 下载地址:http://www.211xun.com/download_page_16.html HALCON 18 是一套机器视觉图像处理库,由一 ...
- 聊聊、Tomcat中文乱码和JVM设置
set JAVA_OPTS=%JAVA_OPTS% -server -Xms512m -Xmx512m -Dfile.encoding=GBK -Dsun.jnu.encoding=GBK
- SQL SERVER存储引擎——04.数据
4. SQL SERVER存储引擎之数据篇 (4.1)文件 (0)主数据文件.mdf初始文件大小至少为3MB,次要数据文件.ndf初始大小,同日志文件一样至少为512KB: (1)SQL SERVER ...
- PHP中create_function的用法总结
在php中,函数create_function主要用来创建匿名函数,有时候匿名函数可以发挥它的作用. 1.测试一 测试一主要用来循环替换数组中多个值的<与>,我们用array_map加上c ...
- AsyncSocket
如果需要在项目中像QQ微信一样做到即时通讯,必须使用socket通讯,本人也是刚学习,分享一下,有什么不对的地方希望大家指正 ios原生的socket用起来不是很直观,所以我用的是AsyncSocke ...
- File(IO流)
import java.io.File; import java.io.IOException; import org.junit.Test; /** *java.io.File类 *1.凡是与输入输 ...
- SPOJ 10628 Count on a tree(Tarjan离线 | RMQ-ST在线求LCA+主席树求树上第K小)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...