题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1664 , 一道比较蛋疼的搜索题。

  这道题有很多坑点,一点处理不好就要TLE。


  题意很简单,就是找到一个n的倍数m,要求m里包含的不同数字最少。

  做这道题要有数论的知识:对于任意的整数n,必然存在一个由不多于两个的数来组成的一个倍数。

  所以这里就比较好入手了,就是先搜一个数的情况,没找到的话再搜两个数的情况。

具体解法:

  用BFS来搜索,注意要有两个剪枝:如果当前队列里的结点的字符串的长度要比已经得到的结果的最小长度要长,则退出这次搜索;只有搜到的结点的数模n的余数未出现过,该节点才能入队,不然的话就会造成重复。还有不能在结点里直接保存字符串,所以要用一个前向指针来标记,需要得到字符串的时候进行一遍递归即可。

  用一个结构体来保存结点信息:当前结点模n的余数、前向指针、结点的字符、到该结点的字符串长度。由于数据量比较大,所以要自己手动维护一个队列。

  还有要注意的是,用string生成字符串的时候,ans = c + ans要比ans += c慢很多。

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = + ;
bool vis[maxn];
int MinLen , n , a[];
struct Node {
char ch;
int mod , len , pre; //余数 , 当前长度 , 前指针
} u , v , que[maxn];
string ans , curans; void GetStr(int k) { //用递归来得到字符串信息,注意这里的写法
if(k == -) return;
GetStr(que[k].pre);
curans += que[k].ch;
}
bool cmp(string a , string b) { //比较两个串表示的十进制的大小
if(a.size() > b.size()) return true;
if(a.size() == b.size() && a > b) return true;
return false;
}
bool bfs(int k)
{
memset(vis , , sizeof(vis));
int head = , tail = -; //队列的首尾指针
for(int i = ; i <= k ; i++) {
if(a[i] != ) { //这里是保证第一个数字不为0
u.pre = -;
u.ch = a[i] + '';
u.mod = a[i] % n;
u.len = ;
vis[u.mod] = ;
que[++tail] = u;
}
}
while(head <= tail) {
u = que[head];
if(u.len > MinLen) break; //这里有一个剪枝
for(int i = ; i <= k ; i++) {
v.mod = (u.mod * + a[i]) % n;
v.ch = a[i] + '';
v.len = u.len + ;
v.pre = head;
if(!vis[v.mod]) { //同余判重
que[++tail] = v;
vis[v.mod] = ;
if(v.mod == ) { //搜到了结果
curans = "";
GetStr(tail); //获得字符串
return true;
}
}
}
head++;
}
return false;
}
int main()
{
while(~scanf("%d" , &n) && n)
{
if(n <= ) {
cout << n << endl;
continue;
}
bool flag = false;
MinLen = maxn;
ans = "";
for(int i = ; i <= ; i++) {
a[] = i;
if(bfs()) {
if(!flag || cmp(ans , curans)) {
flag = true;
ans = curans;
MinLen = ans.size();
}
}
}
if(flag) {
cout << ans << endl;
continue;
}
for(int i = ; i <= ; i++) {
for(int j = i + ; j <= ; j++) {
a[] = i; a[] = j;
if(bfs()) {
if(!flag || cmp(ans , curans)) {
flag = true;
ans = curans;
MinLen = ans.size();
}
}
}
}
cout << ans << endl;
}
return ;
}

HDU1664 BFS + 数论 + 剪枝的更多相关文章

  1. UVA - 11882 Biggest Number(dfs+bfs+强剪枝)

    题目大意:给出一个方格矩阵,矩阵中有数字0~9,任选一个格子为起点,将走过的数字连起来构成一个数,找出最大的那个数,每个格子只能走一次. 题目分析:DFS.剪枝方案:在当前的处境下,找出所有还能到达的 ...

  2. hdu1664 bfs+余数判重

    input n 不超过50个例子,n==0结束输入 Sample Input 7 15 16 101 0 output 最少个不同数字的n的倍数的x,若不同数字个数一样,输出最小的x Sample O ...

  3. soj1091 指环王 bfs+hash+剪枝

    原题链接http://acm.scu.edu.cn/soj/problem.action?id=1091 这题的主要解法就是搜索,我用的是bfs,用map将二维数组处理成字符串作为主键,到达当前状态的 ...

  4. POJ 3278 Catch That Cow[BFS+队列+剪枝]

    第一篇博客,格式惨不忍睹.首先感谢一下鼓励我写博客的大佬@Titordong其次就是感谢一群大佬激励我不断前行@Chunibyo@Tiancfq因为室友tanty强烈要求出现,附上他的名字. Catc ...

  5. hdu 1044(bfs+dfs+剪枝)

    Collect More Jewels Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  6. hdu6223 Infinite Fraction Path 2017沈阳区域赛G题 bfs加剪枝(好题)

    题目传送门 题目大意:给出n座城市,每个城市都有一个0到9的val,城市的编号是从0到n-1,从i位置出发,只能走到(i*i+1)%n这个位置,从任意起点开始,每走一步都会得到一个数字,走n-1步,会 ...

  7. HDU1495 非常可乐(BFS/数论)

    大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多.但see ...

  8. hdu 2717 Catch That Cow(BFS,剪枝)

    题目 #include<stdio.h> #include<string.h> #include<queue> #include<algorithm> ...

  9. UVA-11882 bfs + dfs + 剪枝

    假设当前已经到达(x,y),用bfs判断一下还可以到达的点有maxd个,如果maxd加上当前已经经过的长度小于当前答案的长度就退出,如果相同,就将bfs搜索到的点从大到小排序,如果连最大序列都无法大于 ...

随机推荐

  1. Android xUtils框架(一) DbUtils

    在DbUtils中,只支持4中数据类型: public enum ColumnDbType { INTEGER("INTEGER"), REAL("REAL") ...

  2. Log4NET的日志框架的使用

    日志信息分类 1.等级由低到高:debug<info<warn<Error<Fatal; 2.区别: debug 级别最低,可以随意的使用于任何觉得有利于在调试时更详细的了解系 ...

  3. Intel MPI 配置与基本使用

    安装 Document 系统配置/含NFS 编译环境 设置 加载 mpivars.[c]sh 脚本. 创建文本文件 mpd.hosts ,其中保存有集群的节点列表,每行一个名字 (只针对开发者) 确保 ...

  4. Spark Runtime概述

    从Spark Runtime的角度来讲由五大核心对象:Master.Worker.Executor.Driver.CoarseGrainedExecutorBacked: Spark在做分布式集群系统 ...

  5. 外企面试,哪有你想象的那么难!(已收埃森哲、NTTDATA等8家外企offer)

    无精疯,一名背包客,大学期间穷游了十余个国家,五十余座城市,也是一位拥有健身教练证的业余健身痴迷者.从大二开始自学Java并开始了第一份实习,后面也是通过自学转到了大数据,之前在一家大数据独角兽实习, ...

  6. Gradle安装配置

    1.构建工具的简单介绍在代码世界中有三大构建工具,ant.Maven和Gradle. 现在的状况是maven和gradle并存,gradle使用的越来越广泛. Maven使用基于XML的配置,Grad ...

  7. 使用jdk的xjc命令由schema文件生成相应的实体类

    xjc D:\operate-process.xsd -d D:\workspace\wmsc\src\main\java -p com.yd.wmsc.util operate-process.xs ...

  8. scau 8616 汽车拉力比赛

          上次我们过了二分图的最佳匹配,现在我们看一道题目,经典的二分图的最佳匹配题目 8616 汽车拉力比赛 时间限制:500MS  内存限制:1000K提交次数:71 通过次数:24 题型: 编 ...

  9. HDU 5792 L - World is Exploding 。容斥原理 + 树状数组 + 离散化

    题目,要求找出有多少对这样的东西,四个数,并且满足num[a]<num[b] &&num[c]>num[d] 要做这题,首先要懂得用树状数组,我设,下面的小于和大于都是严格 ...

  10. Linux Shell中的反引号,单引号,双引号

    反引号位 (`) 位于键盘的Tab键的上方.1键的左方.注意与单引号(')位于Enter键的左方的区别. 在Linux中起着命令替换的作用.命令替换是指shell能够将一个命令的标准输出插在一个命令行 ...