蓝桥杯 PREV-15 格子刷油漆

蓝桥杯PREV - 15格子刷油漆算法解析
这篇博客详细解析了蓝桥杯PREV-15题目的格子刷油漆问题。通过分析起点类型,讨论了从角落和中间开始刷油漆的不同策略。博主提出了一种递归关系来计算从角落出发的方案数,并给出了从中间开始的复杂情况的计算公式。文章提供了完整的思路,帮助读者理解解题过程。

历年试题 PREV-15 格子刷油漆

题目传送门
解析
分析题目我们可以知道刷油漆的的起点可以分为两类,一是在第一列和最后一列的四个格子开始;而是在中间的某个格子开始。
对于从角落开始的方案比较好分析,对于从中间开始的,可以将其分解。
例如:城墙为2*5,假设我们从C格开始刷漆,且先向右再向左刷漆。那么可以以B,G和C,H的交界为分割线,右边部分需要从C出发,最后返回与C同列的对应位置H。左边部分则可以从B或G出发,最后的位置任意。先左后右类似。

A B C D E
F G H I J
因此,我们只需要分析从角落开始刷漆,最终位置为开始位置同列的对应格和最终位置任意的情况的方案。
  • 1.从左上角格子A出发,最终返回左下角格子F
      该情形下,每一列初次只能刷一格,这样才能刷满右边步步返回左下角格子F。每一次向下一列移动有两种选择,故若以i代表格子列数,b[i]代表共有i列时从左上角格子出发,回到左下角的方案数,则有递归关系b[i]=2*b[i]。且b[1]=1,b[2]=2。以此关系可以求出n列时的方案数。
  • 2.从左上角格子A出发,最终位置不确定
      最终位置不确定,既可以在同列的对应位置(1中已求),又可以在非同列的位置(待求)。若以i代表格子列数,a[i]代表共有i列时从左上角格子出发,最终停在非同列对应位置的方案数。最终位置与开始位置不同列,又有两种情况:
  • 2.1.A->B/G->F->G/B:向下一列刷,有两种方案到下一列,然后返回左下角,再刷下一列未刷格子之后,然后有两种方案再到下一列,可见有四种方案到下下列,所以刷完所有格子有4*a[i-2]个方案
  • 2.2.A->F->B/G:向下刷,向下刷完之后有两种方法跳到下一列,刷完剩下的i-1列有2*a[i-1]种方案。

因此,可以得到 a[i]=b[i]+2a[i-1]+4a[i-2](i>=3);且a[1]=1,a[2]=6。

所以,对于n列,从角落出发,最终方案共有4*a[n]种;从中间出发,共有 ∑ i = 2 n − 1 ( 2 × b [ n − i + 1 ] × 2 × a [ i − 1 ] + 2 × b [ i ] × 2 × a [ n − i ] ) \sum_{i=2}^{n-1}(2 \times b[n-i+1] \times 2 \times a[i-1] + 2 \times b[i] \times 2 \times a[n-i]) i=2n1(2

### `p->prev->next=p->next;` 的含义和作用 在双向链表中,每个节点通常包含 `prev` 和 `next` 两个指针,分别指向前驱节点和后继节点。语句 `p->prev->next=p->next;` 的含义是将节点 `p` 的前驱节点的 `next` 指针指向节点 `p` 的后继节点。 具体来说,`p->prev` 表示节点 `p` 的前驱节点,`p->next` 表示节点 `p` 的后继节点。通过 `p->prev->next=p->next;` 这一操作,就跳过了节点 `p`,使得 `p` 的前驱节点直接连接到了 `p` 的后继节点。这是从双向链表中删除节点 `p` 时的关键步骤之一,它更新了链表中 `p` 之前节点的连接关系,保证链表在删除 `p` 后仍然是连续的。 ### `p->next->prev=p->prev;` 的含义和作用 语句 `p->next->prev=p->prev;` 是从双向链表中删除节点 `p` 的另一个关键步骤。`p->next` 表示节点 `p` 的后继节点,`p->prev` 表示节点 `p` 的前驱节点。该语句的作用是将节点 `p` 的后继节点的 `prev` 指针指向节点 `p` 的前驱节点。 通过这一操作,同样跳过了节点 `p`,使得 `p` 的后继节点直接连接到了 `p` 的前驱节点。结合 `p->prev->next=p->next;`,这两条语句共同完成了从双向链表中删除节点 `p` 的操作,保证了链表在删除 `p` 后结构的完整性。 ### 代码示例 以下是一个简单的双向链表节点删除的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义双向链表节点结构 typedef struct Node { int data; struct Node* prev; struct Node* next; } Node; // 删除节点 p 的函数 void deleteNode(Node* p) { if (p == NULL) return; if (p->prev != NULL) { p->prev->next = p->next; } if (p->next != NULL) { p->next->prev = p->prev; } free(p); } int main() { // 创建一些节点 Node* node1 = (Node*)malloc(sizeof(Node)); Node* node2 = (Node*)malloc(sizeof(Node)); Node* node3 = (Node*)malloc(sizeof(Node)); node1->data = 1; node2->data = 2; node3->data = 3; // 连接节点形成双向链表 node1->next = node2; node2->prev = node1; node2->next = node3; node3->prev = node2; // 删除节点 2 deleteNode(node2); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值