-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
43 lines (43 loc) · 47.5 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[ACM阶段复习]]></title>
<url>%2F2019%2F11%2F09%2FACM%E9%98%B6%E6%AE%B5%E5%A4%8D%E4%B9%A0%2F</url>
<content type="text"><![CDATA[1. C/C++ 循环输入C++ :123456789101112131415161718192021222324int a, b;while(cin >> a >> b) { ...}/--------------------------/ cin 是 C++ 的标准输入流,其本身是一个对象,并不存在返回值的概念。 不过经常会有类似于 while(cin >> a) 的调用,这里并不是 cin 的返回值,而是 >> 操作重载函数 istream& operator>>(istream&, T &);的返回值,其中第二个参数由cin>>后续参数类型决定 其返回值类型为 istream& 类型,大多数情况下其返回值为 cin 本身(非 0 值) 只有当遇到 EOF 输入或者复制失败时时,返回值为 0/-------------------------/ cin 是 C++ 编程语言中的标准输入流对象,即 istream 类的对象。cin 主要用于从标准输入读取数据,这里的标准输入,指的是终端的键盘。 此外,cout 是流的对象,即 ostream 类的对象 /-------------------------/ 对象就是把 “类” 实例化 ,也类似于结构体变量的声明,它的创建格式是 类名+对象名,比如有一个已经定义的类 A ,可以这样把A实例化 A a ; a就是你创建的对象。只有创建了对象,类才能发挥作用。 C语言 :方法一 : 123456789101112131415161718192021222324252627282930313233int a, b;while(scanf("%d%d", &a, &b) != EOF) { ...}/-------------------------/ 1. C 语言中 EOF 是什么意思? (1)EOF 是 end of file 的缩写,表示 "文字流"(stream)的结尾。这里的 "文字流" ,可以是文件(file),也可以是标准输入。该宏定义在 stdio.h 中。 (2)EOF 不是特殊字符,而是一个定义在头文件 stdio.h 的常量,一般等于 -1 #define EOF (-1) (3)除了表示文件结尾,EOF 还可以表示标准输入的结尾。但是,标准输入与文件不一样,无法事先知道输入的长度,必须手动输入一个字符,表示到达 EOF。 (4)在 while 循环中以 EOF 作为文件结束标志,这种以 EOF 作为文件结束标志的文件,必须是文本文件。 在文本文件中,数据都是以字符的 ASCII 代码值的形式存放。 我们知道,ASCII 代码值的范围是 0~127,不可能出现-1,因此可以用 EOF 作为文件结束标志。 当读一个文件读到文件最后时,读文件的函数(比如函数fgetc(FILE *fp))就会返回这个常量。 比如常用函数scanf(),返回成功读入的数据个数,如果没有任何数据被成功读入,则返回 EOF。/---------------------------/2. 头文件一般由四部分内容组成: (1) 头文件开头处的版权和版本声明; (2) 预处理块; (3) inline 函数的定义; (4) 函数和类结构声明等。 *** 在头文件中,用 ifndef/define/endif 结构产生预处理块,用 #include 格式来引用库的头文件。头文件的这种结构,是利用 C 语言进行开发软件所通常具备的,属于公有知识 方法二 : 1234567891011121314151617181920int a, b;while(~scanf("%d%d", &a, &b)) { ...}/----------------------------/ -1 的补码: 11111111 按位取反后: 00000000 (即为假) 其它输入情况下(无论是否输入成功) while循环的判断条件为非0 即为真/----------------------------/ scanf函数返回的是成功读入的个数 如果只有a被成功读入,返回值为1; 如果a和b都未被成功读入,返回值为0; Windows下可以通过 Ctrl+z 或者 Ctrl+d 结束循环输入 2. t 组样例输入12345int t;cin >> t;while(t--) { ...} 3. double下不能 直等12345678double a = 5.3;double b = 2.6 + 2.7; //相加时会丢失精度结果: a != b 符号位 指数位 尾数位float: 1 8 23 (bit)double: 1 11 52 (bit) 4. C 语言 double 类型的 printf 问题123456结论:在C语言中,double 类型的读入必须用 "%lf" ;输出要用 "%f" ,但是 "%lf" 也不错解释:double 和 float 的精度是不同的,故存储空间也是不同的,所以如果要读入 double 类型,必须要用 %lf 来读入,以免精度丢失。而输出,由于 printf 中并无对 %lf 的严格定义,故使用 %lf 不一定会出现正确结果。那使用 %f 输出又如何呢?由于 C 语言中的默认参数提升规则,%f 输出的不论是 float 还是 double 都会被提升到双精度进行输出,并不会有精度丢失。 5. 最大公约数12345678910111213141516171819202122232425262728// 1. 递归版int gcd(int a, int b) { if(b == 0) return a; return gcd(b, a % b);}int main() { int a, b; cin >> a >> b; cout << "最大公约数是: " << gcd(a, b) << endl; return 0;}// 2. 循环版int main() { int a, b; cin >> a >> b; int r = a % b; while(r != 0) { a = b; b = r; r = a % b; } cout << "最大公约数是: " << b << endl; return 0;} 6. 冒泡排序1234567891011121314151617181920212223242526272829303132333435363738394041424344454647// 1.从a[1]开始存int n;int a[105];int main() { cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; } for(int i = 1; i < n; i++) { for(int j = 1; j <= n - i; j++) { if(a[j] > a[j + 1]) swap(a[j], a[j + 1]); } } for(int i = 1; i <= n; i++) { cout << a[i] << ' '; } cout << endl; return 0;}// 2.从a[0]开始存int n;int a[105];int main() { cin >> n; for(int i = 0; i < n; i++) { cin >> a[i]; } for(int i = 0; i < n - 1; i++) { for(int j = 0; j < n - i - 1; j++) { if(a[j] > a[j + 1]) { int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; } } } for(int i = 0; i < n; i++) { cout << a[i] << ' '; } cout << endl; return 0;} 7. 二分求根号x (保留4位小数) 12345678910111213141516171819202122#include <iostream>#include <cstdio>#include <cmath>using namespace std;int n;int main() { scanf("%d", &n); double l = 0, r = n; while(l < r) { double mid = (l + r) / 2; if(abs(mid * mid - n) <= 1e-5) { printf("%.4lf\n", mid); return 0; } if(mid * mid > n) r = mid; else l = mid; } return 0;} 8. 贪心例题 : 洛谷 P1007 独木桥9. 博弈论]]></content>
<tags>
<tag>Life isn't about waiting for the storm to pass, it's about learning to dance in the rain。生活不是等待暴风雨过去,而是要学会在雨中跳舞。</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Tarjan 求割点,桥(割边)]]></title>
<url>%2F2019%2F10%2F29%2FTarjan-%E6%B1%82%E5%89%B2%E7%82%B9-%E6%A1%A5-%E5%89%B2%E8%BE%B9%2F</url>
<content type="text"><![CDATA[简介: 割边和割点的定义 仅限于无向图 中。我们可以通过定义以蛮力方式求解出无向图的所有割点和割边, 但这样的求解方式效率低。Tarjan 提出了一种快速求解的方式,通过一次 DFS 就求解出图中所有的割点和割边 1. 定义 割点:无向连通图中,去掉一个顶点及和它相邻的所有边,图中的连通分量数增加,则该顶点称为割点 桥 (割边):无向联通图中,去掉一条边,图中的连通分量数增加,则这条边,称为桥或者割边 割点与桥(割边)的关系:1)有割点不一定有桥, 有桥一定存在割点 2)桥一定是割点依附的边 2. Tarjan算法的原理判断一个顶点是不是割点除了从定义,还可以从DFS(深度优先遍历)的角度出发 我们先通过 DFS 定义两个概念 假设 DFS 中我们从 顶点U 访问到了 顶点V ( 此时 顶点V 还未被访问过 ), 那么我们称 顶点U 为 顶点V 的 父顶点,V 为 U 的 孩子顶点。在 顶点U 之前被访问过的顶点,我们就称之为 U 的 祖先顶点 显然如果 顶点U 的 所有孩子顶点 可以不通过 父顶点U 而访问到 U 的祖先顶点,那么说明此时去掉 顶点U 不影响图的连通性,U就不是割点。相反,如果 顶点U 至少存在一个孩子顶点,必须通过 父顶点U 才能访问到 U 的祖先顶点,那么去掉 顶点U 后,顶点U 的祖先顶点和孩子顶点就不连通了,说明 U 是一个割点。 上图中的箭头表示 DFS 访问的顺序(而不表示有向图),对于 顶点D 而言,D 的孩子顶点可以通过连通 区域1 红色的边回到 D 的祖先 顶点C(此时 C 已被访问过),所以此时 D 不是割点 上图中的连通 区域2 中的顶点,必须通过 D 才能访问到 D 的祖先顶点,所以说此时 D 为割点。再次强调一遍,箭头仅仅表示 DFS 的访问顺序,而不是表示该图是有向图。 这里我们还需要考虑一个特殊情况,就是 DFS 的根顶点(一般情况下是编号为0的顶点),因为根顶点没有祖先顶点。其实根顶点是不是割点也很好判断,如果从根顶点出发,一次 DFS 就能访问到所有的顶点,那么根顶点就不是割点。反之,如果回溯到根顶点后,还有未访问过的顶点,需要在邻接顶点上再次进行 DFS,根顶点就是割点。 (简单来所就是若根顶点的有大于等于 2 个孩子,则根顶点就是割点) 3. Tarjan算法的实现细节1. DFN数组 DFN[i]: 表示该顶点 i 在DFS中的遍历顺序(或者说时间戳) 注意: 我们 DFS 遍历时总是先遍历节点编号小的, 再遍历节点编号大的 每访问到一个未访问过的顶点,访问顺序的值(时间戳)就增加1。子顶点的 DFN 值一定比父顶点的 DFN 值大(但不一定恰好大 1,比如父顶点有两个及两个以上分支的情况)。在访问一个顶点后,它的 DFN 的值就确定下来了,不会再改变。 2. LOW数组 LOW[i]: 表示 DFS 中顶点 i 不通过 父顶点能访问到的祖先顶点中最小的顺序值(或者说时间戳, 也可以说是 DFN值) 3. 实现过程思想体现 : 对于根节点: 计算其子树数量,如果有 2 棵即以上的子树,就是割点。因为如果去掉这个点,这两棵子树就不能互相到达。 对于非根节点: 对于边(u, v),如果 LOW[v]>=DFN[u],此时 u 就是割点。 每个顶点初始的 LOW 值和 DFN 值应该一样 (即最早只能回溯到自身) 在 DFS 中,我们根据情况不断更新 LOW 的值。 有一条边 (u, v), 如果 v 未访问过, 继续 DFS, DFS完之后, LOW[u]=min(LOW[u], LOW[v]); 如果 v 访问过(且 u 不是 v 的父亲) , 就不需要继续 DFS 了,一定有 DFN[v] < DFN[u],LOW[u]=min(LOW[u], DFN[v]) 下面观点来自某位大佬 : (仅供参考理解) 关于 Tarjan 算法,一直有一个很大的争议,就是 LOW[u]=min(LOW[u], DFN[v]); 这句话,如果改成 LOW[u]=min(LOW[u], LOW[v]) 就会wa掉,但是在求强连通分量时却没有问题 根据许多大佬的观点,我想提出自己的一点看法,在求强连通分量时,如果 v 已经在栈中,那么说明 u, v 一定在同一个强连通分量中,所以到最后 LOW[u]=LOW[v] 是必然的,提前更新也不会有问题,但是在求割点时,LOW的定义有了小小的变化,不再是最早能追溯到的祖先,(因为是个无向图)没有意义,应该是最早能绕到的割点,为什么用绕到,是因为是无向边,所以有另一条路可以走,如果把 DFN[v] 改掉就会上翻过头,可能翻进另一个环中,所以 WA 掉,仅是本人的一些个人看法,不知道讲的对不对,请各位指教。 不明白的话看完代码, 画两个环, 手动推一下就明白了~ 来看一个具体的例子 : 模仿程序计算各个顶点的 DFN 值和 LOW 值。下图中 蓝色实线箭头表示已访问过的路径,无箭头虚线表示未访问路径。已访问过的顶点用黄色标记,未访问的顶点用白色标记,DFS 当前正在处理的顶点用绿色表示。带箭头的蓝色虚线表示 DFS 回溯时的返回路径。 1. 当 DFS 走到 顶点H 时,有三个分支,按照遍历顺序(总是先走编号小的节点), 先走 H-I,然后走 H-F,最后走 H-J, 从 H 访问 I 时,顶点I 未被访问过,所以I的 DFN 和 LOW 都为 9。根据 DFS 的遍历顺序,我们应该从顶点I继续访问。 2. 上图表示由 顶点I 访问 顶点D,而此时发现 D 已被访问,当从 D 回溯到 I 时,由于 DFN[D] < DFN[I] 说明 D 是 I 的祖先顶点,所以到现在为止,顶点I 不经过 父顶点H 能访问到的小时间戳为 4 3. 根据 DFS 的原理,我们从 顶点I 回到 顶点H,显然到目前为止 顶点H 能访问到的最小时间戳也是 4(因为我们到现在为止只知道能从 H 可以通过 I 访问到 D ),所以 LOW[H] = 4 4. 现在我们继续执行 DFS,走 H-F 路径,发现 顶点F 已被访问且 DFN[F] < DFN[H],说明 F 是 H 的祖先顶点,但此时 顶点H 能访问的最早时间戳是 4,而 F 的时间戳是 6,依据 LOW 值定义 LOW[H] 仍然为 4 5. 最后我们走 H-J 路径,顶点J 未被访问过所以 DFN[J] = 10 LOW[J] = 10 6. 同理,由 DFS 访问 顶点B,DFN[J] > DFN[B],B为祖先顶点,顶点J 不经过 父顶点H 能访问到的最早时间戳就是 DFN[B],即 LOW[J] = 2 7. 我们从 顶点J 回溯到 顶点H,显然到目前为止顶点H能访问到的最早时间戳就更新为 2(因为我们到现在为止知道了能从 H 访问到 J ),所以 LOW[H] = 2 8. 根据 DFS 原理,我们从 H 回退到 顶点E( H回退到G, G回退到F,F回退到E 的过程省略),所经过的顶点都会更新 LOW 值,因为这些顶点不用通过自己的父顶点就可以和 顶点B 相连。当回溯到 顶点E 时,还有未访问过的顶点,那么继续进行 E-K 分支的 DFS 9. 从 E-K 分支访问到 顶点L 时,顶点K 和 L 的 DFN值 和 LOW值 如上图所示 10. 接着我们继续回溯到了 顶点D(中间过程有所省略),并更新 LOW[D] 11. 最后,按照 DFS 的原理,我们回退到 顶点A,并且求出来了每个顶点的 DFN值 和 LOW值 4. 割点 和 桥(割边) 的判定方法 割点 : 1) 对于根节点 : 若根节点的孩子数大于等于2, 则 根节点为割点 2) 对于非根节点 : 对于边 (u, v), 若 LOW[v] >= DFN[u] ,则点 u 为割点 ( 若 LOW[V] >= DFN[u] 就说明顶点V访问顶点U的祖先顶点,必须通过顶点U,而不存在顶点V到顶点U祖先顶点的其它路径,所以顶点U就是一个割点 ) 桥 (割边) : 对于边 (u, v), 若 LOW[v] > DFN[u], 则 u -> v 这条边为桥 ( 因为不包含节点u ) 需要说明的是: Tarjan 算法从图的任意顶点进行 DFS 都可以得出割点集和割边集 4. 割点代码实现以 洛谷 P3388 为例 代码实现 : 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667#include <iostream>#include <cstring>#include <cstdio>#include <algorithm> using namespace std;const int maxn = 1e6 + 5;int n, m, num_edge, t;int head[maxn], DFN[maxn], LOW[maxn];bool vis[maxn];//DFN[i]:就是时间戳,即在什么时刻搜索到了点i//LOW[i]:则是i点能回溯到的DFN最小的祖先/*如果一条边满足low[v]>=dfn[u],那么u点即为一个割点. 证明:如果存在这样一条边满足这样的性质,那么u的儿子v就永远不会访问到早于u的点,那么也就是说,从v出发形成的环中不会包括u,那么从u断开的话,就会形成两个或多个连通块,满足了割点的需求.*/struct stu { int to, nex;}edge[maxn], ans[maxn];void addedge(int from, int to) { edge[++num_edge].to = to; edge[num_edge].nex = head[from]; head[from] = num_edge;}void tarjan(int u, int fa) { DFN[u] = LOW[u] = ++t; int child = 0; //以fa为根的子树0的个数 for(int i = head[u]; i; i = edge[i].nex) { int v = edge[i].to; if(!DFN[v]) { tarjan(v, fa); LOW[u] = min(LOW[u], LOW[v]); //更新当前节点的low值 if(u != fa && LOW[v] >= DFN[u]) vis[u] = 1; //如果一个点不是根,并且它的儿子在不经过它的情况下无法回到它的父亲,那么它也是割点 if(u == fa) child++; } LOW[u] = min(LOW[u], DFN[v]); } if(child >= 2 && u == fa) vis[u] = 1; //如果一个点是根并且有多于两个子树,就是割点}int main() { scanf("%d%d", &n, &m); int x, y; for(int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); addedge(x, y); addedge(y, x); } for(int i = 1; i <= n; i++) { //图可能不连通 if(!DFN[i]) tarjan(i, i); } int ans = 0; for(int i = 1; i <= n; i++) { if(vis[i]) ans++; } printf("%d\n", ans); for(int i = 1; i <= n; i++) { if(vis[i]) printf("%d ", i); } printf("\n"); return 0;} 5. 桥 (割边) 代码实现给出板子 : 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859/*注意: 若建图后的第i条边为: u -> v 则 第i^1条边为: v -> u (和网络流相同)*/#include <iostream>#include <cstring>#include <cstdio>#include <algorithm> using namespace std;const int maxn = 1e6 + 5;int n, m, t, num_edge;int head[maxn], DFN[maxn], LOW[maxn];bool vis[maxn];struct stu { int to, nex;}edge[maxn];void addedge(int from, int to) { edge[++num_edge].to = to; edge[num_edge].nex = head[from]; head[from] = num_edge;}void tarjan(int u, int Edge) { //Edge:当前是第几条边 u:当前边的儿子节点 DFN[u] = LOW[u] = ++t; ////DFS序标记 for(int i = head[u]; i; i = edge[i].nex) { ////访问所有出边 int v = edge[i].to; //出边 if(!DFN[v]) { //不曾访问过,也就是没有标记,可以认为是儿子节点了 tarjan(v, i); //访问儿子节点v,并且设置边为当前边 LOW[u] = min(LOW[u], LOW[v]); //这就是桥的判定 if(LOW[v] > DFN[u]) vis[i] = vis[i ^ 1] = 1; //重边也是桥 } else if(i != (Edge ^ 1)) LOW[u] = min(LOW[u], DFN[v]); }}int main() { scanf("%d%d", &n, &m); num_edge = 1; int x, y; for(int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); addedge(x, y); addedge(y, x); } for(int i = 1; i <= n; i++) { if(!DFN[i]) tarjan(i, 0); } for(int i = 2; i <= num_edge; i += 2) { if(vis[i]) printf("%d %d\n", edge[i ^ 1].to, edge[i].to); } return 0;} 例题 :洛谷 P1656 代码实现 : 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#include <iostream>#include <cstring>#include <cstdio>#include <algorithm> using namespace std;const int maxn = 1e6 + 5;int n, m, t, num_edge;int head[maxn], DFN[maxn], LOW[maxn];bool vis[maxn];struct stu { int to, nex;}edge[maxn], ans[maxn];bool cmp(stu x, stu y) { if(x.to == y.to) return x.nex < y.nex; return x.to < y.to;}void addedge(int from, int to) { edge[++num_edge].to = to; edge[num_edge].nex = head[from]; head[from] = num_edge;}void tarjan(int u, int Edge) { //Edge:当前是第几条边 u:当前边的儿子节点 DFN[u] = LOW[u] = ++t; ////DFS序标记 for(int i = head[u]; i; i = edge[i].nex) { ////访问所有出边 int v = edge[i].to; //出边 if(!DFN[v]) { //不曾访问过,也就是没有标记,可以认为是儿子节点了 tarjan(v, i); //访问儿子节点v,并且设置边为当前边 LOW[u] = min(LOW[u], LOW[v]); //这就是桥的判定 if(LOW[v] > DFN[u]) vis[i] = vis[i ^ 1] = 1; //重边也是桥 } else if(i != (Edge ^ 1)) LOW[u] = min(LOW[u], DFN[v]); }}int main() { scanf("%d%d", &n, &m); num_edge = 1; int x, y; for(int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); addedge(x, y); addedge(y, x); } for(int i = 1; i <= n; i++) { if(!DFN[i]) tarjan(i, 0); } int tt = 0; for(int i = 2; i <= num_edge; i += 2) { if(vis[i]) { ans[++tt].to = min(edge[i].to, edge[i ^ 1].to); ans[tt].nex = max(edge[i].to, edge[i ^ 1].to); } } sort(ans + 1, ans + tt + 1, cmp); for(int i = 1; i <= tt; i++) { printf("%d %d\n", ans[i].to, ans[i].nex); } return 0;} 6. 参考网址传送门 1 传送门 2]]></content>
<tags>
<tag>One today is worth two tomorrows. 一个今天胜似两个明天</tag>
</tags>
</entry>
<entry>
<title><![CDATA[字典树 (Trie 树)]]></title>
<url>%2F2019%2F09%2F11%2F%E5%AD%97%E5%85%B8%E6%A0%91%2F</url>
<content type="text"><![CDATA[1. 引入字典是干啥的?查找字的。 字典树自然也是起查找作用的。查找的是啥?单词。 看以下几个题: 1) 给出n个单词和m个询问,每次询问一个单词,回答这个单词是否在单词表中出现过。 答:简单!map,短小精悍。 好。下一个 2) 给出n个单词和m个询问,每次询问一个前缀,回答询问是多少个单词的前缀。 答:map,把每个单词拆开。 judge:n<=200000,TLE! 这就需要一种高级数据结构——Trie树(字典树) 2. 原理在本篇文章中,假设 所有单词都只由小写字母 构成 对cat,cash,app,apple,aply,ok 建一颗字典树,建成之后如下图所示 由此可以看出: 1、字典树用边表示字母 2、有相同前缀的单词公用前缀节点,那我们可以的得出每个节点最多有26个子节点(在单词只包含小写字母的情况下) 3、整棵树的根节点是空的。为什么呢?便于插入和查找,这将会在后面解释。 4、每个单词结束的时候用一个特殊字符表示,图中用的‘′,那么从根节点到任意一个‘′,那么从根节点到任意一个‘’所经过的边的所有字母表示一个单词。 3. 基本操作1. insert 插入一个单词思路: 从图中可以直观看出,从左到右扫这个单词,如果字母在相应根节点下没有出现过,就插入这个字母;否则沿着字典树往下走,看单词的下一个字母。 这就产生一个问题:往哪儿插?计算机不会自己选择位置插,我们需要给它指定一个位置,那就需要给每个字母编号。 我们设数组trie[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点。 什么意思呢? 这里有2种编号,一种是i,k表示节点的位置编号,这是相对整棵树而言的;另一种是j,表示节点i的第j的孩子,这是相对节点i而言的。 不理解?看图 还是单词cat,cash,app,apple,aply,ok 我们就按输入顺序对其编第一种号,红色表示编号结果。因为先输入的cat,所以c,a,t分别是1,2,3,然后输入的是cash,因为c,a是公共前缀,所以从s开始编,s是4,以此类推。 注意这里相同字母的编号可能不同 第二种编号,相对节点的编号,紫色表示编号结果。 因为每个节点最多有26个子节点,我们可以按他们的字典序从0——25编号,也就是他们的ASCLL码-a的ASCLL码。 注意这里相同字母的编号相同 实际上每个节点的子节点都应该从0编到——25,但这样会发现许多事根本用不到的。比如上图的根节点应该分出26个叉。节约空间,用到哪个分哪个。 这样编号有什么用呢? 回到数组trie[i][j]=k。 数组trie[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点。 那么第二种编号即为j,第一种编号即为i,k 代码实现: 12345678910void insert() { //插入单词s len = strlen(s); //单词s的长度 root = 0; //根节点编号为0 for(int i = 0; i < len; i++) { int id = s[i] - 'a'; //第二种编号 if(!trie[root][id]) //如果之前没有从root到id的前缀 trie[root][id] = ++tot; //插入,tot即为第一种编号 root = trie[root][id]; //顺着字典树往下走 }} 2. search 查找思路: 从左往右以此扫描每个字母,顺着字典树往下找,能找到这个字母,往下走,否则结束查找,即没有这个前缀;前缀扫完了,表示有这个前缀。 代码实现: 1234567891011bool find() { len = strlen(s); root = 0; //从根结点开始找 for(int i = 0; s[i]; i++) { int x = s[i] - 'a';// if(trie[root][x] == 0) return false; //以root为头结点的x字母不存在,返回0 root = trie[root][x]; //为查询下个字母做准备,往下走 } return true;//找到了} 3、如果是查询某个单词的话,我们用bool变量 v[i]表示节点i是否是单词结束的标志。 那么最后return的是v[root],所以在插入操作中插入完每个单词是,要对单词最后一个字母的v[i]置为true,其他的都是false 4、如果是查询前缀出现的次数的话,那就在开一个sum[],表示位置i被访问过的次数 那么最后return的是sum[root],插入操作中每访问一个节点,都要让他的sum++ 这里前缀的次数是标记在前缀的最后一个字母所在位置的后一个位置上。 比如:前缀abc出现的次数标记在c所在位置的后一个位置上 3. 完整代码实现1. 查询是否出现 (前缀 或 全部) 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556/* trie tree的储存方式:将字母储存在边上,边的节点连接与它相连的字母 trie[rt][x]=tot:rt是上个节点编号,x是字母,tot是下个节点编号 */ #include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#define maxn 2000010using namespace std;int tot = 1, n;int trie[maxn][26];//bool isw[maxn];查询整个单词用void insert(char *s, int rt) { for(int i = 0; s[i]; i++) { int x = s[i] - 'a'; if(trie[rt][x] == 0) { //现在插入的字母在之前同一节点处未出现过 trie[rt][x] = ++tot;//字母插入一个新的位置,否则不做处理 } rt = trie[rt][x];//为下个字母的插入做准备 } /*isw[rt] = true;标志该单词末位字母的尾结点,在查询整个单词时用到*/}bool find(char *s, int rt) { for(int i = 0; s[i]; i++) { int x = s[i] - 'a'; if(trie[rt][x] == 0) return false; //以rt为头结点的x字母不存在,返回0 rt = trie[rt][x]; //为查询下个字母做准备 } return true; //查询整个单词时,应该return isw[rt] }char s[22];int main() { tot = 0; int rt = 0; scanf("%d", &n); for(int i = 1; i <= n; i++) { cin >> s; insert(s, rt); } scanf("%d", &n); for(int i = 1; i <= n; i++) { cin >> s; if(find(s, rt)) printf("YES\n"); else printf("NO\n"); } return 0;} 2. 查询前缀出现次数 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int trie[400001][26], len, root, tot, sum[400001];char s[12];void insert(char *s) { len = strlen(s); root = 0; for(int i = 0; i < len; i++) { int id = s[i] - 'a'; if(!trie[root][id]) trie[root][id] = ++tot; sum[trie[root][id]]++; //前缀保存 root = trie[root][id]; }}int search(char *s) { root = 0; len = strlen(s); for(int i = 0; i < len; i++) { int id = s[i] - 'a'; if(!trie[root][id]) return 0; root = trie[root][id]; } //root经过此循环后变成前缀最后一个字母所在位置 return sum[root];}int n, m;int main() { char s[12]; scanf("%d", &n); for(int i = 1; i <= n; i++) { cin >> s; insert(s); } scanf("%d", &m); for(int i = 1; i <= m; i++) { cin >> s; printf("%d\n", search(s)); }} 参考网址: 网址]]></content>
<tags>
<tag>All things come to those who wait. 苍天不负有心人</tag>
</tags>
</entry>
<entry>
<title><![CDATA[基础博弈]]></title>
<url>%2F2019%2F09%2F08%2F%E5%9F%BA%E7%A1%80%E5%8D%9A%E5%BC%88%2F</url>
<content type="text"><![CDATA[基础博弈1. 博弈论的简介 博弈论是二人或多人在平等的对局中各自利用对方的策略变换自己的对抗策略,达到取胜目标的理论。博弈论是研究互动决策的理论。博弈可以分析自己与对手的利弊关系,从而确立自己在博弈中的优势,因此有不少博弈理论,可以帮助对弈者分析局势,从而采取相应策略,最终达到取胜的目的。博弈的类型分为:合作博弈、非合作博弈、完全信息博弈、非完全信息博弈、静态博弈、动态博弈,等等。 2. 基础概念 必胜态:通过某一步可以转移到必败态的局面。 也就是说,对于一个处于必胜态的玩家,他总能找到一种合法操作,将当前局面变成一个必败态然后交给对方,如果中途不出现意外的话,最终自己就会得到胜利。但是处于必胜态并不意味着任意的操作都能将当前局面变成必败态。 必败态:通过某一步只能转移到必胜态的局面。 也就是说,处于必败态的玩家无论做什么操作,都只会将当前的局面变成必胜态,然后交给对方,只要对方足够聪明,那么该玩家将输掉比赛。 对于足够聪明的两个博弈者来说,游戏的胜负在比赛前就已经知道(当然,我这里只是说在题目里,在现实中如果是稍微复杂一点的博弈游戏,单凭人脑是很难达到那种水平),也就是说胜利的一方总能找到胜利的路径,而输掉的那一方无论怎样走,胜利的一方都能找到对应的方法。也就是说先后手以及起始局面可以决定整场博弈的胜负。 3. 巴什博弈(Bash Game) 只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。 求 r=n%(1+m), 判断 r 是否等于 0,如果 r 不等于 0,先手必胜,否则后手必胜。为什么? 我们可以分析一下,对于 n=(1+m) * r+s,如果 s不等于 0 的话,先手取走s,那么总的物品数剩下 (1+m) * r,然后后手取走 k 的话,先手只要取走 1+m-k 的物品,就可以保持 n=(1+m) 的倍数的局面交给对方,这意味着什么?意味着 n=0 的局面最终会被后手得到,那样后手就输了。而如果s等于0的话,那么对于先手取k的物品,后手只要取 1+m-k 个物品就可以将n=0的局面转给先手,先手就输了。 所以这里的必败态是(1+m)的倍数。有没有发现,对于一场博弈来说,所有的必败态都会有相似的地方,就像这里,必败态一定是(1+m)的倍数。 然后再说深一点的巴什博弈:只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取p个,最多取q个,如果剩下的物品数小于p的话需要一次取完。最后取光者得胜。 这个又怎样求?按照上面的思路,我们可以得到公式n=(p+q)*r+s。 那么这里的s有两种情况①s>=p,②s<p,。 对于①很容易分析,只要先手取走s的话,对于后手去k,先手只要取p+q-k即可保证先手必胜。 对于②,分析起来没有①那么简单,所以这可能就一定需要用后面讲到的用SG值来判断了。 然后在讲一下一个问题。如果条件和基本的巴什博弈基本一样,但是说的是最后谁是无法再取物品的是赢家的话,那该怎么处理呢? 既然是这样,先手只要判断一下能不能将最后一步留给自己就可以了。而最后一步最少也要保留一个物品,所以我们可以将这个问题转化为基本的巴什博弈,只是终点变成一个物品,而不是零个物品。所以判断的条件是(n-1)%(1+m)!=0 ? 先手赢 : 后手赢。 代码实现 : 1234int Bash_Game(int n,int m) { //是否先手有必赢策略 if (n % (1 + m) != 0) return 1; //先手赢 return 0; //后手赢} 例题:1. HDU1846 (模板题) http://acm.hdu.edu.cn/showproblem.php?pid=1846 12345678910111213141516#include <iostream>using namespace std;int main() { int t; cin >> t; while(t--) { int n, m; cin >> n >> m; int s = n % (1 + m); if(s) cout << "first" << endl; else cout << "second" << endl; } return 0;} 2. HDU4764 (巴什博弈变形) http://acm.hdu.edu.cn/showproblem.php?pid=4764 12345678910111213#include <iostream>using namespace std;int main() { int n, m; while(cin >> n >> m && n && m) { int s = (n - 1) % (1 + m); //谁先写到 大于等于n 谁就输 if(s) cout << "Tang" << endl; else cout << "Jiang" << endl; } return 0;} 4. 尼姆博弈(Nimm Game) 和 扩展 有若干堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。 12345678910111213141516171819求 r=n%(1+m), 判断 r 是否等于 0,如果 r 不等于 0,先手必胜,否则后手必胜。为什么? 我们可以分析一下,对于 n=(1+m) * r+s,如果 s不等于 0 的话,先手取走s,那么总的物品数剩下 (1+m) * r,然后后手取走 k 的话,先手只要取走 1+m-k 的物品,就可以保持 n=(1+m) 的倍数的局面交给对方,这意味着什么?意味着 n=0 的局面最终会被后手得到,那样后手就输了。而如果s等于0的话,那么对于先手取k的物品,后手只要取 1+m-k 个物品就可以将n=0的局面转给先手,先手就输了。 所以这里的必败态是(1+m)的倍数。有没有发现,对于一场博弈来说,所有的必败态都会有相似的地方,就像这里,必败态一定是(1+m)的倍数。 然后再说深一点的巴什博弈:只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取p个,最多取q个,如果剩下的物品数小于p的话需要一次取完。最后取光者得胜。 这个又怎样求?按照上面的思路,我们可以得到公式n=(p+q)*r+s。 那么这里的s有两种情况①s>=p,②s<p,。 对于①很容易分析,只要先手取走s的话,对于后手去k,先手只要取p+q-k即可保证先手必胜。 对于②,分析起来没有①那么简单,所以这可能就一定需要用后面讲到的用SG值来判断了。 然后在讲一下一个问题。如果条件和基本的巴什博弈基本一样,但是说的是最后谁是无法再取物品的是赢家的话,那该怎么处理呢? 既然是这样,先手只要判断一下能不能将最后一步留给自己就可以了。而最后一步最少也要保留一个物品,所以我们可以将这个问题转化为基本的巴什博弈,只是终点变成一个物品,而不是零个物品。所以判断的条件是(n-1)%(1+m)!=0 ? 先手赢 : 后手赢。 代码实现: 12345678int Nimm_Game(int n) { //假设n个数存在数组f[]中,有必胜策略返回1 int flag = 0; for(int i = 1; i <= n; i++) { flag ^= f[i]; } if(flag) return 1; //先手赢 return 0; //后手赢} 例题:1. 洛谷 P2197 (尼姆博弈 模板) https://www.luogu.org/problem/P2197 1234567891011121314151617181920#include <iostream>#include <cstring>using namespace std;int main() { int t; cin >> t; while(t--) { int n, x, ans = 0;; cin >> n; for(int i = 1; i <= n; i++) { cin >> x; ans ^= x; } if(ans) cout << "Yes" << endl; else cout << "No" << endl; } return 0;} 扩展: 求 第一次/每次 取出的数量 123456789101112131415161718192021// 第一次从b堆中取出a个这个游戏的SG值就是各堆数量的异或和,当 SG 为 0 时先手必败,否则先手就要把SG变为0先检验 SG 值,如果是 0 输出 lose,否则我们按照以下原则行动--//----重点来了------有 n 个数的异或值不为 0 现在要减少一个数使异或值为 0假设 n 个数:a1 ,a2,a3...ana1^a2^a3^..^an=k那么我们可以对一个数进行操作,假设这个数是a1,设 a1^k = a', a'^a2^a3^...^an = a1^a2^a3^...^an^k = k^k = 0;所以我们只需要从头到尾检验每个数异或k的值是否比它小(因为是要减少),遇到小的直接输出 ai-ai^k 即可//在这里要明白: 假设把每堆石子的数量异或以后得到数为 k (k!=0) 这里 k 并不是第一次要取出 k 个石子 在这里设用 k 去与每堆f[i]异或得到的一个数为 m 若 m < f[i], 则说明第一次是在 第i堆中取了f[i]-k^f[i]个石子 例题:1. 洛谷 P1427 (第一次取出) https://www.luogu.org/problem/P1247 123456789101112131415161718192021222324252627282930#include <iostream> using namespace std;int n;int k[500005];int main() { int ans = 0; cin >> n; for(int i = 1; i <= n; i++) { cin >> k[i]; ans ^= k[i]; } if(!ans) { cout << "lose" << endl; return 0; } for(int i = 1; i <= n; i++) { if((ans ^ k[i]) >= k[i]) continue; cout << k[i] - (ans ^ k[i]) << ' '<< i << endl; k[i] ^= ans; break; } for(int i = 1; i <= n; i++) { cout << k[i] << ' '; } cout << endl; return 0;} 2. HDU 2176 (每次 取出/剩余 ) http://acm.hdu.edu.cn/showproblem.php?pid=2176 12345678910111213141516171819202122232425262728#include <iostream> using namespace std;int n;int k[500005];int main() { while(cin >> n && n) { int ans = 0; for(int i = 1; i <= n; i++) { cin >> k[i]; ans ^= k[i]; } if(!ans) { cout << "No" << endl; continue; } cout << "Yes" << endl; for(int i = 1; i <= n; i++) { if((ans ^ k[i]) >= k[i]) continue; int t = ans ^ k[i]; //t是按照最优的方法取完石子后,剩下的石子 cout << k[i] << ' '<< t << endl; } } return 0;}]]></content>
<tags>
<tag>Better late than never. 只要开始,虽晚不迟.</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux下使用 Github + Hexo 搭建私人博客]]></title>
<url>%2F2019%2F09%2F08%2FLinux%E4%B8%8B%E4%BD%BF%E7%94%A8-Github-Hexo-%E6%90%AD%E5%BB%BA%E7%A7%81%E4%BA%BA%E5%8D%9A%E5%AE%A2%2F</url>
<content type="text"><![CDATA[在此声明: 注意输入命令时当前的路径, 没有标注的话就是任意路径 一. 搭建Hexo1. Node.js安装首先去官网下载格式为 tar.xz 的安装包 官网链接, 然后解压 然后执行命令 12345678910111213//此操作通过创建软链接执行,语法格式为 ln -s 源文件 目标文件,参数-s为软链接(符号链接)[root@changjianing]# ln -s /home/changjianing/Downloads/node-v10.16.3-linux-x64/bin/node /usr/local/bin/node[root@changjianing]# ln -s /home/changjianing/Downloads/node-v10.16.3-linux-x64/bin/npm /usr/local/bin/npm//(这里注意版本区别)//如果显示: /usr/local/bin/node已存在 或 /usr/local/bin/npm已存在就到这个路径(/usr/local/bin/node),把node删了再次执行此命令或就到这个路径(/usr/local/bin/npm),把npm删了再次执行此命令 2. 安装 gitsudo apt-get install git 给一个学习 git 的网站 Git教程 3. 安装 HexoHexo 操作命令官网 官网链接 (了解) npm install hexo-cli -g //安装Hexo 若此命令不能执行,则进行以下操作 (安装npm) 1234567//npm的源在国外,没翻墙的话速度会很慢,可以改成国内的淘宝源 (执行以下3行命令)npm config set registry https://registry.npm.taobao.orgnpm config listsudo apt-get install npm//然后再安装 Hexonpm install hexo-cli -g (或 npm install -g hexo-cli) 此处安装完成后,需要将Hexo添加到全局变量中。否则会提示找不到命令 ln -s /home/changjianing/Downloads/node-v10.16.3-linux-x64/lib/node_modules/hexo-cli/bin/hexo /usr/local/bin/hexo 4. 部署 Hexo 博客环境1) 部署 Hexo 可以放在和 Node.js 同层级的目录 1234567891011121314151617[root@changjianing Downloads]# pwd/home/changjianing/Downloads[root@changjianing Downloads]# mkdir hexo[root@changjianing Downloads]# cd hexo/[root@changjianing hexo]# hexo init # 新建一个网站,默认在目前的文件夹建立网站。[root@changjianing hexo]# ll //ll不行 可以lstotal 168-rw-r--r-- 1 root root 1765 Jun 4 16:14 _config.ymldrwxr-xr-x 285 root root 12288 Jun 4 16:15 node_modules-rw-r--r-- 1 root root 443 Jun 4 16:14 package.json-rw-r--r-- 1 root root 138442 Jun 4 16:15 package-lock.jsondrwxr-xr-x 2 root root 4096 Jun 4 16:14 scaffoldsdrwxr-xr-x 3 root root 4096 Jun 4 16:14 sourcedrwxr-xr-x 3 root root 4096 Jun 4 16:14 themes[root@changjianing hexo]# ll themes/ # 查看自带的主题total 4drwxr-xr-x 6 root root 4096 Jun 4 16:14 landscape 2) 启动环境测试 123456789101112131415[root@changjianing hexo]# hexo g # 生成静态文件[root@changjianing hexo]# lltotal 200-rw-r--r-- 1 root root 1765 Jun 4 16:14 _config.yml-rw-r--r-- 1 root root 25063 Jun 4 16:26 db.jsondrwxr-xr-x 285 root root 12288 Jun 4 16:15 node_modules-rw-r--r-- 1 root root 447 Jun 4 16:26 package.json-rw-r--r-- 1 root root 138442 Jun 4 16:15 package-lock.jsondrwxr-xr-x 7 root root 4096 Jun 4 16:26 public # 生成的静态文件drwxr-xr-x 2 root root 4096 Jun 4 16:14 scaffoldsdrwxr-xr-x 3 root root 4096 Jun 4 16:14 sourcedrwxr-xr-x 3 root root 4096 Jun 4 16:14 themes[root@changjianing hexo]# hexo s # 启动服务,默认是 http://localhost:4000INFO Start processingINFO Hexo is running at http://localhost:4000 . Press Ctrl+C to stop. 3) 浏览器访问 (选择执行) 123http://www.zhangblog.com:4000///下面给出别人的访问情况, 自己的没有截图 访问情况 二. 将 Hexo 和 Github Pages 结合1. 注册 Github 账号Github 官网 2. 使用Github Pages创建指定的Github仓库, 点击创建按钮 仓库名称和配置选择 开启 Github Pages, 进入 Settings 默认已开启 Github Pages 选择主题, 并查看 具体情况 浏览器访问 1https://zhanglianghhh.github.io/ 访问情况 3. 在Github 上添加 SSH秘钥 并配置1234567891011121314151617181920212223242526272829303132[root@changjianing ~]# ssh-keygen -t rsa # 如果遇见等待输入的地方,按下 Enter 回车键即可,无需任何其他输入Generating public/private rsa key pair.Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa.Your public key has been saved in /root/.ssh/id_rsa.pub.The key fingerprint is:SHA256:73zrQW4LTBgAVqQKvOoTxFrgaGF/sobf643Q+3w7or0 root@zhangblogThe key's randomart image is:+---[RSA 2048]----+| o++ ||oo . . . ||*oo . . ||.*o+ . o ||+oo + S . . ||oo o. + o ||. +... + + ||.. ...*. = o.o || .. .*+E+.=o+. |+----[SHA256]-----+[root@changjianing ~]# cd .ssh/[root@changjianing .ssh]# lltotal 12-rw------- 1 root root 0 Jun 3 17:02 authorized_keys-rw------- 1 root root 1675 Jun 5 14:17 id_rsa-rw-r--r-- 1 root root 396 Jun 5 14:17 id_rsa.pub-rw-r--r-- 1 root root 395 Dec 14 17:15 known_hosts[root@changjianing .ssh]# cat id_rsa.pub # 具体的公钥信息ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD4iDDDDDDDDDDgMMutdH7KdI5P7BrtHbfRG+MYyr1/Gtz45hJgbVHBCTFZaTn2+MekFQcZVkyc2kEU7L7mm4ZGWkStgbXkas+uTFwo3kLlX8ozcUC3jM8rhzbWPv8piq58ezBnrMZ0zNsCgHGXpokUmLqYt1mpLXz5rsOzwGgHHkp+Wlr+6tTQxr/+9T4CiE/RkFKi/mehn01rjOcVluYSkwkVii03EzMlMcoyV3ctnWzwyZIWAQAsvDSN2CQAdRtaUHOJOAoRv8/s4jDiWU1ia0JYmm2D/IWcLl2hxNtGeVHTFk9l1djtUQu47zuoOM4y6ySlUx28HNIAMw14gjIv5 root@zhangblog Github 添加 SSH秘钥 Github 连接测试 1234567[root@changjianing ~]# ssh -T [email protected] authenticity of host 'github.com (13.250.177.223)' can't be established.RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.RSA key fingerprint is MD5:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.Are you sure you want to continue connecting (yes/no)? yes //输入yes就行Warning: Permanently added 'github.com,13.250.177.223' (RSA) to the list of known hosts.Hi zhanglianghhh! You've successfully authenticated, but GitHub does not provide shell access. 可见连接 Github 成功 4. 设置账号信息123[root@changjianing hexo]# git config --global user.name "zhanglianghhh" //这里填写你创建网站的名字[root@changjianing hexo]# git config --global user.email "[email protected]" //这里填写你Github上的邮箱 5. Hexo 部署到 Github Pages_config.yml 配置修改 1234567891011[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo //注意这里的路径(搭建Hexo时创建的hexo文件夹)[root@changjianing hexo]# vim _config.yml………………# Deployment## Docs: https://hexo.io/docs/deployment.html # 修改或添加如下信息deploy: type: git repo: [email protected]:zhanglianghhh/zhanglianghhh.github.io.git //填写自己的信息 branch: master 在部署到 GitHub 之前,还需要安装如下扩展: 1234[root@changjianing hexo]# pwd # 站点目录/home/changjianing/Downloads/hexo[root@changjianing hexo]# npm install hexo-deployer-git --save 部署到 Github 1234[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo[root@changjianing hexo]# hexo d -g # 部署前,先生成静态文件 -g 可选 浏览器访问 12https://zhanglianghhh.github.io/ # GitHub Pages 的访问http://www.zhangblog.com/ # 个人网站的访问 三. 更换 Hexo主题1. 进入官网挑选喜欢的主题Hexo主题官网 可以看到有很多主题给我们选,我们只要选择喜欢的主题点击进去,然后进入到它的github地址,我们只要把这个地址复制下来(例如我是选择:hexo-theme-next这个主题) 2. 克隆主题再打开 hexo文件夹下的 themes 目录 1234[root@changjianing themes]# pwd/home/changjianing/Downloads/hexo/themes[root@changjianing themes]# git clone https://github.com/iissnan/hexo-theme-next(此处地址替换成你需要使用的主题的地址) 下载中,等待下载完成 3. 修改hexo配置文件下载完成后, 打开 hexo 中的 _config.yml 文件 123456[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo[root@changjianing hexo]# vim _config.yml//修改参数为: theme: hexo-theme-next 4. 部署主题, 本地查看效果返回 hexo 目录 12345[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo[root@changjianing hexo]# hexo g[root@changjianing hexo]# hexo s 打开浏览器,输入 http://localhost:4000/ 即可看见我们的主题已经更换了 5. 如果效果满意, 就将它部署到 Github 上12345[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo[root@changjianing hexo]# hexo clean //必须要,不然有时因为缓存问题,服务器更新不了主题[root@changjianing hexo]# hexo g -d 6. 打开自己的主页, 即可查看效果更多具体修改请查看对应主题的说明文档 四. 新建/删除 博客文章1. 用 hexo 发表新文章12345678910111213[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo[root@changjianing hexo]# hexo n "文章标题" //-----其中 我的家 为文章标题,执行命令 hexo n "我的家" 后会在项目 \hexo\source_posts 中生成 我的家.md文件,用编辑器打开编写即可当然,也可以直接在 \hexo\source\_posts 中新建一个 md 文件,我就是这么做的。 写完后,推送到服务器上,执行以下命令即可在我们的站点看到新的文章。 //如果执行命令: hexo n "文章标题" 出现未找到命令//则需重装Hexo,执行次命令即可: npm install hexo-cli -g 然后执行以下操作 12345[root@changjianing hexo]# pwd/home/changjianing/Downloads/hexo[root@changjianing hexo]# hexo g //生成[root@changjianing hexo]# hexo d //部署 打开自己的主页,即可查看效果 2. 删除文章删除文章的过程一样也很简单,先删除本地文件,然后通过生成和部署命令进而将远程仓库中的文件也一并删除。具体来说,以最开始默认形成的 helloworld.md 这篇文章为例。 首先进入到 /home/changjianing/hexo/source/_post 文件夹中,找到 helloworld.md 文件,在本地直接执行删除 然后执行以下操作: 12[root@changjianing hexo]# hexo g //生成[root@changjianing hexo]# hexo d //部署 然后去主页即可查看效果 五. 参考网址1. 搭建 Hexo 2. 将 Hexo 和 Github Pages 结合 3. 更换 Hexo 主题 和 新建文章 4. 删除文章]]></content>
<tags>
<tag>Do what you say,say what you do. 做你说过的,说你能做的</tag>
</tags>
</entry>
</search>