Chapter 1 递归与递推

  • 时间复杂度(转载自yxc大佬)

一般ACM或者笔试题的时间限制是1秒或2秒。

在这种情况下,C++代码中的操作次数控制在 107107 为最佳。

下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:

n≤30n≤30, 指数级别, dfs+剪枝,状态压缩dp

n≤100n≤100 => O(n3)O(n3),floyd,dp

n≤1000n≤1000 => O(n2)O(n2),O(n2logn)O(n2logn),dp,二分

n≤10000n≤10000 => O(n∗n√)O(n∗n),块状链表

n≤100000n≤100000 => O(nlogn)O(nlogn) => 各种sort,线段树、树状数组、set/map、heap、dijkstra+heap、spfa、求凸包、求半平面交、二分

n≤1000000n≤1000000 => O(n)O(n), 以及常数较小的 O(nlogn)O(nlogn) 算法 => hash、双指针扫描、kmp、AC自动机,常数比较小的 O(nlogn)O(nlogn) 的做法:sort、树状数组、heap、dijkstra、spfa

n≤10000000n≤10000000 => O(n)O(n),双指针扫描、kmp、AC自动机、线性筛素数

n≤109n≤109 => O(n√)O(n),判断质数

n≤1018n≤1018 => O(logn)O(logn),最大公约数

cin cout 与 scanf printf 如何选择

如果处理数据个数小于10 ^ 5,都可以

如果处理数据个数大于等于10 ^ 5,建议用 scanf printf

  • 递归 dfs

1.递归实现指数型枚举 92

可以画递归搜索树帮助理解分析

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std; const int maxn = 15;
int m;
int a[maxn];//存放数字状态 0 未考虑, 1选 2不选 void pit (int n){
if(n == m){
for(int i = 0; i < maxn; i++)
if(a[i] == 1) printf("%d ", i + 1);
printf("\n");
return;
}
a[n] = 2;
pit(n + 1);//第一个分支
a[n] = 0;//恢复现场 (可有可无 帮助理解)
a[n] = 1;
pit(n + 1);//第二个分支
} int main()
{
while(cin >> m){
pit(0);
}
return 0;
}
2.递归实现排列型枚举 94
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
//按照字典序输出
using namespace std; int m;
const int maxn = 10;
bool used[maxn];//检查每个数字是否被用过, false表示没被用过,true表示用过了
int st[maxn];//0表示还没存放数字 1~m表示已经存放,存放的是谁 void dfs(int n)
{
if(n > m)
{
for(int i = 1; i <= m; i++)
printf("%d ", st[i]);
puts("");
return;
}
for(int i = 1; i <= m; i++)
if(!used[i]){
st[n] = i;
used[i] = true;
dfs(n + 1);
//恢复现场
st[n] = 0;
used[i] = false;
}
} int main()
{
scanf("%d", &m);
dfs(1);
return 0;
}
3.递归实现组合型枚举 93
  • Time limit exceeded
//答案对,会超时!!(下面有第二种方法)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm> using namespace std; const int maxn = 50;
int n, m;
int st[maxn];//0表示这一位没有数字占用,1~n表示有并且是谁占用
bool used[maxn];//false表示没有用过,true表示已经用过 void dfs(int i)
{
if(i > m)
{
int flag = 1;
for(int j = 1; j < m ; j++)
if(st[j + 1] < st[j]){ flag = 0; break;}
if(flag)
{
for(int j = 1; j <= m; j++)
printf("%d ", st[j]);
puts("");
}
return;
}
for(int j = 1; j <= n; j++)
if(!used[j]){
st[i] = j;
used[j] = true;
dfs(i + 1);
//恢复现场
st[i] = 0;
used[j] = false;
} } int main()
{
scanf("%d%d", &n, &m);
dfs(1);
return 0;
}
  • AC code
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm> using namespace std; const int maxn = 30;
int n, m;
int st[maxn]; void dfs(int u, int start)//start用来确保下一位必定比前一位要大
{
if(u + n - start < m) return;//减支,提高程序运行效率
if(u > m){//边界
for(int i = 1; i <= m; i++)
printf("%d ", st[i]);
puts("");
return;
}
for(int i = start; i <= n; i++)
{
st[u] = i;
dfs(u + 1, i + 1);
//恢复状态,可有可无 帮助理解
st[u] = 0;
}
} int main()
{
scanf("%d%d", &n, &m);
dfs(1, 1);
return 0;
}
4.带分数 1209
//y总答案
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; typedef long long LL; const int N = 10; int n;
bool st[N], backup[N];
int ans; bool check(int a, int c)
{
LL b = n * (LL)c - a * c; if (!a || !b || !c) return false; memcpy(backup, st, sizeof st); while (b)
{
int x = b % 10; // 取个位
b /= 10; // 个位删掉
if (!x || backup[x]) return false;
backup[x] = true;
} for (int i = 1; i <= 9; i ++ )
if (!backup[i])
return false; return true;
} void dfs_c(int u, int a, int c)
{
if (check(a, c)) ans ++ ; for (int i = 1; i <= 9; i ++ )
if (!st[i])
{
st[i] = true;
dfs_c(u + 1, a, c * 10 + i);
st[i] = false;
}
} void dfs_a(int u, int a)
{
if (a >= n) return;
if (a) dfs_c(u, a, 0); for (int i = 1; i <= 9; i ++ )
if (!st[i])
{
st[i] = true;
dfs_a(u + 1, a * 10 + i);
st[i] = false;
}
} int main()
{
cin >> n; dfs_a(0, 0); cout << ans << endl; return 0;
}
  • 递推

1.简单的斐波那契
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; int n;
int fb[1000000]; int main()
{
cin >> n;
fb[0] = 0;
fb[1] = 1;
for(int i = 2; i < n; i++)
fb[i] = fb[i - 1] + fb[i - 2];
for(int i = 0; i < n; i++)
printf("%d ", fb[i]);
return 0;
}
2.费解的开关 95
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; int dx[5] = {0, 0, 1, 0, -1}, dy[5] = {0, 1, 0, -1, 0};//坐标偏移变量
const int maxn = 6;
char g[maxn][maxn], backup[maxn][maxn];//backup为备份数组 void turn(int x, int y)
{
for(int i = 0; i < 5; i++)
{
int a = x + dx[i], b = y + dy[i];
if(a < 0 || a >= 5 || b < 0 || b >=5) continue;
g[a][b] ^= 1;
}
} int main()
{
int n;
cin >> n;
while(n--)
{
for(int i = 0; i < 5; i++) cin >> g[i];
int step = 10;
for(int i = 0; i < 32; i++)//第一行有32种情况,二进制0/1表示是否操作
{
int res = 0;
memcpy(backup, g, sizeof g);
for(int j = 0; j < 5; j++)
if(i >> j & 1)
{
res++;
turn(0, 4 - j);//没搞懂,为什么不是turn(0, 4 - j);
}
for(int i = 0; i < 4; i++)
for(int j = 0; j < 5; j++)
if(g[i][j] == '0')
{
res++;
turn(i + 1, j);
}
bool dark = false;
for(int i = 0; i < 5; i++)
if(g[4][i] == '0') {dark = true; break;}
if(!dark) step = min(step, res);
memcpy(g, backup, sizeof g);
}
if(step > 6) step = -1;//变量很巧妙,用了在for循环外层就定义的step用min来承接res
cout << step << endl;
}
return 0;
}
3.飞行员兄弟 116

step 1: 计算复杂度 2 ^ 16 * (16 * 7 + 16 + 16)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector> using namespace std; typedef pair<int , int> PII; #define x first
#define y second const int maxn = 5;
char g[maxn][maxn], backup[maxn][maxn]; int code(int i, int j)//因为要字典序输出坐标,所以为了方便把二维数组标号
{
return i * 4 + j;
} void turn_one(int x, int y)
{
if(g[x][y] == '+') g[x][y] = '-';
else g[x][y] = '+';
} void turn_all(int x, int y)
{
for(int i = 0; i < maxn - 1; i++)
{
turn_one(x, i);
turn_one(i, y);
}
turn_one(x, y);//(x, y)turn了两次,需要再turn回来
} int main()
{
for(int i = 0; i < maxn - 1; i++) cin >> g[i];
vector<PII> res;//承担结果的PII定义位置
for(int op = 0; op < 1 << 16; op++)
{
vector<PII> temp; memcpy(backup, g, sizeof g);//枚举前的备份,因为要修改 for(int i = 0; i < maxn - 1; i++)
for(int j = 0; j < maxn - 1; j++)
{
int res = 0;
if(op >> code(i, j) & 1)//巧妙的移位让输出的坐标已经是字典序排行
{
temp.push_back({i, j});
turn_all(i, j);
res++;
}
} bool has_closed = false;//判断有没有灯是灭的
for(int i = 0; i < maxn - 1; i++)
for(int j = 0; j < maxn - 1; j++)
if(g[i][j] == '+')
has_closed = true;
if(!has_closed)
if(res.empty() || res.size() > temp.size()) res = temp;
memcpy(g, backup, sizeof g);
} cout << res.size() << endl;
for(auto zm : res) cout << zm.x + 1 << " " << zm.y + 1 << endl; return 0;
}
4.翻硬币 1208
//虽然说要输出最少次数,实验推演之后可以知道其实只有唯一的结果
//想象每两个硬币中间有一个决定是否翻面的开关
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; const int maxn = 105;
char begin1[maxn], end1[maxn];
int s, res; void turn(int u)
{
if(begin1[u] == 'o') {begin1[u] = '*';return;}
if(begin1[u] == '*') {begin1[u] = 'o';return;}
} int main()
{
cin >> begin1 >> end1;
s = strlen(begin1);
for(int i = 0; i < s - 1; i++)
if(begin1[i] != end1[i])
{
turn(i);
turn(i + 1);
res++;
}
cout << res << endl;
return 0;
}

Chapter1 递归与递推的更多相关文章

  1. 斐波那契数列 递归 尾递归 递推 C++实现

    ==================================声明================================== 本文原创,转载请注明作者和出处,并保证文章的完整性(包括本 ...

  2. 动态规划——数字三角形(递归or递推or记忆化搜索)

    动态规划的核心就是状态和状态转移方程. 对于该题,需要用抽象的方法思考,把当前的位置(i,j)看成一个状态,然后定义状态的指标函数d(i,j)为从格子出发时能得到的最大和(包括格子本身的值). 在这个 ...

  3. 剑指offer-矩形覆盖-斐波那契数列(递归,递推)

    class Solution { public: int rectCover(int number) { if(number==0 || number==1||number==2) return nu ...

  4. P1044 栈(递归、递推、卡特兰、打表)

    P1044 栈 题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表. 栈有两种最重要的操作,即pop(从栈顶弹出一个元素)和push(将一个元素进栈). 栈的重要 ...

  5. NOI / 2.3基本算法之递归变递推-6262:流感传染

    OpenJudge - 6262:流感传染http://noi.openjudge.cn/ch0203/6262/ 6262:流感传染​​​​​​ 总时间限制: 1000ms 内存限制: 65536k ...

  6. 从一道NOI练习题说递推和递归

    一.递推: 所谓递推,简单理解就是推导数列的通项公式.先举一个简单的例子(另一个NOI练习题,但不是这次要解的问题): 楼梯有n(100 > n > 0)阶台阶,上楼时可以一步上1阶,也可 ...

  7. 从三数之和看如何优化算法,递推-->递推加二分查找-->递推加滑尺

    人类发明了轮子,提高了力的使用效率. 人类发明了自动化机械,将自己从重复的工作中解脱出来. 提高效率的方法好像总是离不开两点:拒绝无效劳动,拒绝重复劳动.人类如此,计算机亦如是. 前面我们说过了四数之 ...

  8. 【uva 12627】Erratic Expansion(算法效率--递推)

    题意:初始1个红气球,每小时后,1个红气球会变成3个红气球和1个蓝气球,而1个蓝气球会变成4个蓝气球.问经过N小时后,第L~R行一共有多少个红气球. 解法:问行数就定义f[i][j]表示 i 小时后前 ...

  9. 百练2755 奇妙的口袋 【深搜】or【动规】or【普通递归】or【递推】

    总Time Limit:  10000ms  Memory Limit:  65536kB 有一个奇妙的口袋.总的容积是40,用这个口袋能够变出一些物品,这些物品的整体积必须是40.John如今有n个 ...

随机推荐

  1. tmobst6an

    (单选题)Oracle数据库中,在SQL语句中连接字符串的方法是:(). A)CAT B)CONCAT C)JOIN D)UNION 解析:Oracle可以使用CONCAT关键字或"||&q ...

  2. VS下解决_CRT_SECURE_NO_WARNINGS 警告

    1.带有警告的文件加 #define _CRT_SECURE_NO_WARNINGS 2.右击工程 - 属性 - 配置属性 - C/C++  - 命令行 命令行增加 /D _CRT_SECURE_NO ...

  3. hadoop 日常使用记录

    1.Hadoop分布式文件系统(HDFS) HDFS基于GFS(Google File System),能够存储海量的数据,并且使用分布式网络客户端透明访问. HDFS中将文件拆分成特定大小的块结构( ...

  4. Codeforces_731_C

    http://codeforces.com/problemset/problem/731/C 并查集,然后找每个集合里颜色的最大数量,求集合中元素数量-这个最大数量,最后总数相加即答案. #inclu ...

  5. CCF_ 201412-1_门禁系统

    水. #include<iostream> #include<cstdio> using namespace std; int main() { ],num[] = {}; c ...

  6. 一台电脑上配置多个git的ssh key

    前几天公司的代码库全部迁移到了阿里云上,在配置git的ssh key的时候遇到了一个问题,那就是自己的密钥在添加时提示已经存在,原来是自己的个人账号上已经添加过这个密钥了,公司分配的账号就不能再添加这 ...

  7. NLP(二十一)人物关系抽取的一次实战

      去年,笔者写过一篇文章利用关系抽取构建知识图谱的一次尝试,试图用现在的深度学习办法去做开放领域的关系抽取,但是遗憾的是,目前在开放领域的关系抽取,还没有成熟的解决方案和模型.当时的文章仅作为笔者的 ...

  8. OSPF笔记——LSA及其字段,及其作用

    Link State ID Link State ID remains at 32 bits in length, Link State ID has shed any addressing sema ...

  9. 配置ASA防火墙 远程管理方式

          受不了,asa和思科路由器 系统命令不一致,这一篇专门来写asa.      先看下版本 asa825# show version      Cisco Adaptive Security ...

  10. 小浩算法|一文让你学会如何用代码判断"24"点

    “24点”是一种数学游戏,正如象棋.围棋一样是一种人们喜闻乐见的娱乐活动.它始于何年何月已无从考究,但它以自己独具的数学魅力和丰富的内涵正逐渐被越来越多的人们所接受.今天就为大家分享一道关于“24点” ...