前言

在知乎上看到了一篇神奇的文章:

哪段代码最能代表程序员的暴力美学

深感 C++ 宏替换功能前途不可小觑,觉得是时候搞一波事情了(手动滑稽)。

编译器内存超限

最开始的时候,我想写一个解八皇后的程序,过程中先写了一个枚举八个元素全排列的程序:

/// 利用编译器的计算能力来进行常数优化 #include <iostream>
using namespace std;int arr[9], vis[9], cnt = 0; /// 用于枚举 全排列 #define put8(x) if(!vis[x]){vis[x]=1;arr[8]=x;cnt++;vis[x]=0;}
#define set8    put8(1);put8(2);put8(3);put8(4);put8(5);put8(6);put8(7);put8(8);#define put7(x) if(!vis[x]){vis[x]=1;arr[7]=x;set8;vis[x]=0;}
#define set7    put7(1);put7(2);put7(3);put7(4);put7(5);put7(6);put7(7);put7(8);#define put6(x) if(!vis[x]){vis[x]=1;arr[6]=x;set7;vis[x]=0;}
#define set6    put6(1);put6(2);put6(3);put6(4);put6(5);put6(6);put6(7);put6(8);#define put5(x) if(!vis[x]){vis[x]=1;arr[5]=x;set6;vis[x]=0;}
#define set5    put5(1);put5(2);put5(3);put5(4);put5(5);put5(6);put5(7);put5(8);#define put4(x) if(!vis[x]){vis[x]=1;arr[4]=x;set5;vis[x]=0;}
#define set4    put4(1);put4(2);put4(3);put4(4);put4(5);put4(6);put4(7);put4(8);#define put3(x) if(!vis[x]){vis[x]=1;arr[3]=x;set4;vis[x]=0;}
#define set3    put3(1);put3(2);put3(3);put3(4);put3(5);put3(6);put3(7);put3(8);#define put2(x) if(!vis[x]){vis[x]=1;arr[2]=x;set3;vis[x]=0;}
#define set2    put2(1);put2(2);put2(3);put2(4);put2(5);put2(6);put2(7);put2(8); /// 尝试所有可能 #define put1(x) if(!vis[x]){vis[x]=1;arr[1]=x;set2;vis[x]=0;}
#define set1    put1(1);put1(2);put1(3);put1(4);put1(5);put1(6);put1(7);put1(8);int main() {set1;cout << cnt << endl;return 0;
}

我用 g++ define.cpp -o define 命令,将这个文件在 ubuntu 20.04 系统下进行了编译,经过了长达十几分钟的艰苦奋战(电脑内存占用几乎时时刻刻都是 95% 以上),编译器终于缴械投降了。

define.cpp: In function ‘int main()’:
define.cpp:8:26: internal compiler error: Segmentation fault8 | #define put8(x) if(!vis[x]){vis[x]=1;arr[8]=x;cnt++;vis[x]=0;}|                          ^
define.cpp:9:33: note: in expansion of macro ‘put8’9 | #define set8    put8(1);put8(2);put8(3);put8(4);put8(5);put8(6);put8(7);put8(8);|                                 ^~~~
define.cpp:11:47: note: in expansion of macro ‘set8’11 | #define put7(x) if(!vis[x]){vis[x]=1;arr[7]=x;set8;vis[x]=0;}|                                               ^~~~
define.cpp:12:25: note: in expansion of macro ‘put7’12 | #define set7    put7(1);put7(2);put7(3);put7(4);put7(5);put7(6);put7(7);put7(8);|                         ^~~~
define.cpp:14:47: note: in expansion of macro ‘set7’14 | #define put6(x) if(!vis[x]){vis[x]=1;arr[6]=x;set7;vis[x]=0;}|                                               ^~~~
define.cpp:15:25: note: in expansion of macro ‘put6’15 | #define set6    put6(1);put6(2);put6(3);put6(4);put6(5);put6(6);put6(7);put6(8);|                         ^~~~
define.cpp:17:47: note: in expansion of macro ‘set6’17 | #define put5(x) if(!vis[x]){vis[x]=1;arr[5]=x;set6;vis[x]=0;}|                                               ^~~~
define.cpp:18:49: note: in expansion of macro ‘put5’18 | #define set5    put5(1);put5(2);put5(3);put5(4);put5(5);put5(6);put5(7);put5(8);|                                                 ^~~~
define.cpp:20:47: note: in expansion of macro ‘set5’20 | #define put4(x) if(!vis[x]){vis[x]=1;arr[4]=x;set5;vis[x]=0;}|                                               ^~~~
define.cpp:21:17: note: in expansion of macro ‘put4’21 | #define set4    put4(1);put4(2);put4(3);put4(4);put4(5);put4(6);put4(7);put4(8);|                 ^~~~
define.cpp:23:47: note: in expansion of macro ‘set4’23 | #define put3(x) if(!vis[x]){vis[x]=1;arr[3]=x;set4;vis[x]=0;}|                                               ^~~~
define.cpp:24:41: note: in expansion of macro ‘put3’24 | #define set3    put3(1);put3(2);put3(3);put3(4);put3(5);put3(6);put3(7);put3(8);|                                         ^~~~
define.cpp:26:47: note: in expansion of macro ‘set3’26 | #define put2(x) if(!vis[x]){vis[x]=1;arr[2]=x;set3;vis[x]=0;}|                                               ^~~~
define.cpp:27:41: note: in expansion of macro ‘put2’27 | #define set2    put2(1);put2(2);put2(3);put2(4);put2(5);put2(6);put2(7);put2(8); /// �������п���|                                         ^~~~
define.cpp:29:47: note: in expansion of macro ‘set2’29 | #define put1(x) if(!vis[x]){vis[x]=1;arr[1]=x;set2;vis[x]=0;}|                                               ^~~~
define.cpp:30:25: note: in expansion of macro ‘put1’30 | #define set1    put1(1);put1(2);put1(3);put1(4);put1(5);put1(6);put1(7);put1(8);|                         ^~~~
define.cpp:33:2: note: in expansion of macro ‘set1’33 |  set1;|  ^~~~
mmap: Cannot allocate memory
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions.

场面一度十分尴尬。后来我试了试 n<8n < 8n<8 的情况,最后终于成功的计算出了 n=6n = 6n=6 的情况下的全排列。

/// 利用编译器的计算能力来进行常数优化 #include <iostream>
using namespace std;int arr[9], vis[9], cnt = 0; /// 用于枚举 全排列 #define put6(x) if(!vis[x]){vis[x]=1;arr[6]=x;cnt++;vis[x]=0;}
#define set6    put6(1);put6(2);put6(3);put6(4);put6(5);put6(6);#define put5(x) if(!vis[x]){vis[x]=1;arr[5]=x;set6;vis[x]=0;}
#define set5    put5(1);put5(2);put5(3);put5(4);put5(5);put5(6);#define put4(x) if(!vis[x]){vis[x]=1;arr[4]=x;set5;vis[x]=0;}
#define set4    put4(1);put4(2);put4(3);put4(4);put4(5);put4(6);#define put3(x) if(!vis[x]){vis[x]=1;arr[3]=x;set4;vis[x]=0;}
#define set3    put3(1);put3(2);put3(3);put3(4);put3(5);put3(6);#define put2(x) if(!vis[x]){vis[x]=1;arr[2]=x;set3;vis[x]=0;}
#define set2    put2(1);put2(2);put2(3);put2(4);put2(5);put2(6); /// 尝试所有可能 #define put1(x) if(!vis[x]){vis[x]=1;arr[1]=x;set2;vis[x]=0;}
#define set1    put1(1);put1(2);put1(3);put1(4);put1(5);put1(6);int main() {set1;cout << cnt << endl;return 0;
}

总之还是编译了十多秒。

改名

标识符的名字短点的话是否能让编辑过程消耗的内存少一些呢?

/// 利用编译器的计算能力来进行常数优化 #include <iostream>
using namespace std;#define vis v
#define arr aint arr[9], vis[9], cnt = 0; /// 用于枚举 全排列
inline void D(int x) {vis[x] = 0;}
inline void V(int x) {vis[x] = 1;}
inline void C() {cnt ++;}
inline void A(int id, int x) {arr[id] = x;}#define P8(x) if(!vis[x]){V(x);A(8,x);C();D(x);}
#define S8    P8(1);P8(2);P8(3);P8(4);P8(5);P8(6);P8(7);P8(8);#define P7(x) if(!vis[x]){V(x);A(7,x);S8;D(x);}
#define S7    P7(1);P7(2);P7(3);P7(4);P7(5);P7(6);P7(7);P7(8);#define P6(x) if(!vis[x]){V(x);A(6,x);S7;D(x);}
#define S6    P6(1);P6(2);P6(3);P6(4);P6(5);P6(6);P6(7);P6(8);#define P5(x) if(!vis[x]){V(x);A(5,x);S6;D(x);}
#define S5    P5(1);P5(2);P5(3);P5(4);P5(5);P5(6);P5(7);P5(8);#define P4(x) if(!vis[x]){V(x);A(4,x);S5;D(x);}
#define S4    P4(1);P4(2);P4(3);P4(4);P4(5);P4(6);P4(7);P4(8);#define P3(x) if(!vis[x]){V(x);A(3,x);S4;D(x);}
#define S3    P3(1);P3(2);P3(3);P3(4);P3(5);P3(6);P3(7);P3(8);#define P2(x) if(!vis[x]){V(x);A(2,x);S3;D(x);}
#define S2    P2(1);P2(2);P2(3);P2(4);P2(5);P2(6);P2(7);P2(8); /// 尝试所有可能 #define P1(x) if(!vis[x]){V(x);A(1,x);S2;D(x);}
#define S1    P1(1);P1(2);P1(3);P1(4);P1(5);P1(6);P1(7);P1(8);int main() {S1;cout << cnt << endl;return 0;
}

很不幸的是,编译最终还是因为内存不足而失败了。

测试最大展开

#include <cstdio>int cnt = 0;
inline void P(int i) {cnt ++;
}#define D1(i) P(i);
#define D2(i) D1(i);D1(i+1);
#define D4(i) D2(i);D2(i+2);
#define D8(i) D4(i);D4(i+4);
#define DA(i) D8(i);D8(i+8);  /// DA: D16
#define DB(i) DA(i);DA(i+16); /// DB: D32
#define DC(i) DB(i);DB(i+32); /// DC: D64
#define DD(i) DC(i);DC(i+64); /// DD: D128
#define DE(i) DD(i);DD(i+128); /// DE: D256
#define DF(i) DE(i);DE(i+256); /// DF: D512
#define DG(i) DF(i);DF(i+512); /// DG: D1024
#define DH(i) DG(i);DG(i+1024); /// DH: D2048
#define DI(i) DH(i);DH(i+2048); /// DI: D4096
#define DJ(i) DI(i);DI(i+4096); /// DJ: D8192
#define DK(i) DJ(i);DJ(i+8192); /// DK: D16384
#define DL(i) DK(i);DK(i+16384); /// DL: D32768
#define DM(i) DL(i);DL(i+32768); /// DM: D65536
#define DN(i) DM(i);DM(i+65536); /// DN: D131072
#define DO(i) DN(i);DN(i+131072); /// DO: D262144int main() {DN(0); ///DO(0); 会导致编译器崩溃 printf("%d\n", cnt);return 0;
}

在我的电脑上,上述程序能够成功展开至 131072131072131072,但是当展开至 262144262144262144 时,编译因内存不足失败。

因此可以借助这个程序进行 1∼n(n≤131072)1\sim n\;(n\leq 131072)1∼n(n≤131072) 的循环展开。

#include <cstdio>int cnt = 0;
inline void P(int i) {cnt ++;
}#define D1(i) P(i);
#define D2(i) D1(i);if(i+1<=n){D1(i+1);}
#define D4(i) D2(i);if(i+2<=n){D2(i+2);}
#define D8(i) D4(i);if(i+4<=n){D4(i+4);}
#define DA(i) D8(i);if(i+8<=n){D8(i+8);}  /// DA: D16
#define DB(i) DA(i);if(i+16<=n){DA(i+16);} /// DB: D32
#define DC(i) DB(i);if(i+32<=n){DB(i+32);} /// DC: D64
#define DD(i) DC(i);if(i+64<=n){DC(i+64);} /// DD: D128
#define DE(i) DD(i);if(i+128<=n){DD(i+128);} /// DE: D256
#define DF(i) DE(i);if(i+256<=n){DE(i+256);} /// DF: D512
#define DG(i) DF(i);if(i+512<=n){DF(i+512);} /// DG: D1024
#define DH(i) DG(i);if(i+1024<=n){DG(i+1024);} /// DH: D2048
#define DI(i) DH(i);if(i+2048<=n){DH(i+2048);} /// DI: D4096
#define DJ(i) DI(i);if(i+4096<=n){DI(i+4096);} /// DJ: D8192
#define DK(i) DJ(i);if(i+8192<=n){DJ(i+8192);} /// DK: D16384
#define DL(i) DK(i);if(i+16384<=n){DK(i+16384);} /// DL: D32768
#define DM(i) DL(i);if(i+32768<=n){DL(i+32768);} /// DM: D65536
#define DN(i) DM(i);if(i+65536<=n){DM(i+65536);} /// DN: D131072
#define DO(i) DN(i);if(i+131072<=n){DN(i+131072);} /// DO: D262144int main() {int n = 1000;DN(0); ///DO(0); 会导致编译器崩溃 printf("%d\n", cnt);return 0;
}

经过了 202020 多秒的漫长编译,上述程序得出了正确的计算结果 100110011001。

循环展开实践

输入 nnn 个数,输出这 nnn 个数的和。

#include <cstdio>int cnt = 0, A[10001];
inline void input(int i) {scanf("%d", &A[i]);
}
inline void sum(int i) {cnt += A[i];
}#define D1(i) P(i);
#define D2(i) D1(i);if(i+1<=n){D1(i+1);}
#define D4(i) D2(i);if(i+2<=n){D2(i+2);}
#define D8(i) D4(i);if(i+4<=n){D4(i+4);}
#define DA(i) D8(i);if(i+8<=n){D8(i+8);}  /// DA: D16
#define DB(i) DA(i);if(i+16<=n){DA(i+16);} /// DB: D32
#define DC(i) DB(i);if(i+32<=n){DB(i+32);} /// DC: D64
#define DD(i) DC(i);if(i+64<=n){DC(i+64);} /// DD: D128
#define DE(i) DD(i);if(i+128<=n){DD(i+128);} /// DE: D256
#define DF(i) DE(i);if(i+256<=n){DE(i+256);} /// DF: D512
#define DG(i) DF(i);if(i+512<=n){DF(i+512);} /// DG: D1024
#define DH(i) DG(i);if(i+1024<=n){DG(i+1024);} /// DH: D2048
#define DI(i) DH(i);if(i+2048<=n){DH(i+2048);} /// DI: D4096
#define DJ(i) DI(i);if(i+4096<=n){DI(i+4096);} /// DJ: D8192
#define DK(i) DJ(i);if(i+8192<=n){DJ(i+8192);} /// DK: D16384
#define DL(i) DK(i);if(i+16384<=n){DK(i+16384);} /// DL: D32768
#define DM(i) DL(i);if(i+32768<=n){DL(i+32768);} /// DM: D65536
#define DN(i) DM(i);if(i+65536<=n){DM(i+65536);} /// DN: D131072
#define DO(i) DN(i);if(i+131072<=n){DN(i+131072);} /// DO: D262144int main() {int n; scanf("%d", &n);#define P inputDK(1); ///DO(0); 会导致编译器崩溃 #undef P#define P sumDK(1);#undef Pprintf("%d\n", cnt);return 0;
}

程序可以通过编译并得出正确的结果。

无循环冒泡排序

光是想一想就觉得很爽。

#include <cstdio>#define D1(i) P(i);
#define D2(i) D1(i);if(i+1<=n){D1(i+1);}
#define D4(i) D2(i);if(i+2<=n){D2(i+2);}
#define D8(i) D4(i);if(i+4<=n){D4(i+4);}
#define DA(i) D8(i);if(i+8<=n){D8(i+8);}  /// DA: D16
#define DB(i) DA(i);if(i+16<=n){DA(i+16);} /// DB: D32
#define DC(i) DB(i);if(i+32<=n){DB(i+32);} /// DC: D64
#define DD(i) DC(i);if(i+64<=n){DC(i+64);} /// DD: D128
#define DE(i) DD(i);if(i+128<=n){DD(i+128);} /// DE: D256
#define DF(i) DE(i);if(i+256<=n){DE(i+256);} /// DF: D512
#define DG(i) DF(i);if(i+512<=n){DF(i+512);} /// DG: D1024
#define DH(i) DG(i);if(i+1024<=n){DG(i+1024);} /// DH: D2048
#define DI(i) DH(i);if(i+2048<=n){DH(i+2048);} /// DI: D4096
#define DJ(i) DI(i);if(i+4096<=n){DI(i+4096);} /// DJ: D8192
#define DK(i) DJ(i);if(i+8192<=n){DJ(i+8192);} /// DK: D16384
#define DL(i) DK(i);if(i+16384<=n){DK(i+16384);} /// DL: D32768
#define DM(i) DL(i);if(i+32768<=n){DL(i+32768);} /// DM: D65536
#define DN(i) DM(i);if(i+65536<=n){DM(i+65536);} /// DN: D131072
#define DO(i) DN(i);if(i+131072<=n){DN(i+131072);} /// DO: D262144#define LOOP(i) for(int t=i;t<=n;t+=1024){DG(t);} /// 实现循环展开 int n;int cnt = 0, A[10001];inline void input(int i) {scanf("%d", &A[i]);
}
void put(int x) {if(x > 9) put(x/10);putchar('0' + x%10);
}
inline void output(int i) {put(A[i]); putchar(' '); /// 输出优化
}void nxt(int i) {if(A[i-1] > A[i]) {int t = A[i-1]; A[i-1] = A[i]; A[i] = t;}
}void line(int i) { /// 进行一轮冒泡 #define P nxtLOOP(2);#undef P
}int main() {scanf("%d", &n);#define P input /// 输入数据 LOOP(1);#undef P#define P line /// 冒泡 LOOP(1);#undef P#define P output /// 输出 LOOP(1);#undef Preturn 0;
}

洛谷 U165361 bubble-sort 冒泡排序测试处

使用C++#define进行循环与递归展开相关推荐

  1. 入门C语言第三话:数组之实战篇——扫雷(进阶版——图形化界面,递归展开,播放音乐与音效,标记取消雷,记录雷的个数,鼠标点击,文末附有完整代码)

    文章目录 前言 每日鸡汤 基本思路 衔接基础班扫雷 准备阶段 正文 一.雷盘信息的存储 1.设置雷盘11*11与初始化 2.放置雷 3.放置雷周围的信息 二.图形化界面 1.创建与初始化窗口 2.加载 ...

  2. 硬币找零——背包问题,以及循环、递归、动规共通性

    在这个题目的基础上,我了解了一下这几个"编程写法",并对循环.递归.dp有了新的想法.从原理上,这几个想法都是大事化小.小事化了.只不过方向不同罢了. 根据The Algorith ...

  3. C语言实现扫雷(内含递归展开)

    游戏规则: (1)取胜条件:由玩家找到9x9地图中的10个雷即胜利 (2)结束条件:取胜或者不幸触雷 (3)补充细则:在判断出不是雷的方块上按下左键,可以打开该方块.如果方块上出现数字,则该数字表示其 ...

  4. 【C语言扫雷游戏详解及如何实现递归展开】

    提示:全文已采用物理深色模式,请放心观看 文章目录 一.整体框架 1.设计思路 2.实现细节 二.主要函数 1.打印棋盘 2.递归展开 三.其他函数 一.整体框架 1.设计思路 基础难度的扫雷游戏含有 ...

  5. C语言 扫雷(含递归展开)

    目录 前言 一.设计思路 基本的构思方向 准备基本框架 二.函数功能设置 菜单界面 主函数 初始化 显示棋盘 设置雷 计算周围雷数 排雷 总体game函数 后续优化 1.标记雷 2.递归展开 3.防止 ...

  6. 算法设计与分析之循环与递归

    前言: 循环与递归可以说是算法设计中最基本但却也是最重要的工具方法.循环和递归对于学习过高级程序设计语言的人来说都并不陌生,但还是有必要仔细的探究一下循环和递归之间的相似和区别.循环与递归最大的相似之 ...

  7. 如何利用循环代替递归以防止栈溢出(译)

    摘要:我们经常会用到递归函数,但是如果递归深度太大时,往往导致栈溢出.而递归深度往往不太容易把握,所以比较安全一点的做法就是:用循环代替递归.文章最后的原文里面讲了如何用10步实现这个过程,相当精彩. ...

  8. 记一次数据结构与算法作业:利用循环和递归输出1-N的正整数的程序分析比较

    随便记录一次数据结构与算法的分析作业,内容为分析循环和递归实现输出1-N的正整数的对比.从时间和空间上分析了两种方式实现的递归方法和循环区别. 一.数据记录图表 二.分析 第一张图表制作时由于在打游戏 ...

  9. 【深度学习(deep learning)】花书第10章 序列建模:循环和递归网络 读书笔记

    [深度学习(deep learning)]花书第10章 序列建模:循环和递归网络 读书笔记 第10章 序列建模:循环和递归网络 [深度学习(deep learning)]花书第10章 序列建模:循环和 ...

最新文章

  1. 新兴AI解决方案将越来越依赖于嵌入式视觉技术
  2. 利用 CSS selector 改变悬停表格样式
  3. Hostonly cookie是什么鬼?
  4. Codeforces 671C Ultimate Weirdness of an Array 线段树 (看题解)
  5. html 圆环实现多种颜色,SVG实现多彩圆环倒计时效果的示例代码
  6. Kronos Research推出结合WOO质押机制的新资管产品规模已达1500万美元
  7. solve stiffness matrix in matlab
  8. Django【设计】可插拔的插件方式实现
  9. oracle的unload,Oracle 业务数据unload恢复过程
  10. matlab为uigetfile设置默认打开地址(打开路径)
  11. Maven第9篇:多环境构建
  12. STM32 Bootloader开发记录 3 固件签名校验
  13. 黄金分割法求函数最小值
  14. 明解C语言入门篇_第10章_指针
  15. win10修改中文用户名
  16. jquery 遍历java对象_jquery遍历数组、对象
  17. iOS高性能Model转换框架----YYModel学习
  18. bitbucket安装
  19. java ocx调用_Java调用ocx控件以及dll
  20. 如果想进入IT行业工作,需要做准备吗?

热门文章

  1. 关于前置++和后置++的小题
  2. 冷笑话精选冷兔一句话冷笑话精选,脑筋急转弯冷笑话精选段子小明滚出去
  3. 怎么优雅的在主线程获取子线程的返回值
  4. 亚马逊防关联(收藏 一生受用)
  5. [论文笔记] the book of why 1.因果推断三步骤:关联、干预、反事实推断
  6. 【校招VIP】线上实习 推推 书籍详情模块 产品脑图周最佳
  7. 关于dojo的build系统
  8. 染布厂ERP新员工培训流程(中山宏瑞计算机科技有限公司编辑)
  9. Visualsfm与meshlab三维重建
  10. php stripslashes()函数,PHP stripslashes 函数