ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

积木画

2022-05-22 11:01:54  阅读:164  来源: 互联网

标签:10 状态 int 积木 画布 方格


积木画

小明最近迷上了积木画,有这么两种类型的积木,分别为 $I$ 型(大小为 $2$ 个单位面积)和 $L$ 型(大小为 $3$ 个单位面积):

同时,小明有一块面积大小为 $2 \times N$ 的画布,画布由 $2 \times N$ 个 $1 \times 1$ 区域构成。

小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式?

积木可以任意旋转,且画布的方向固定。

输入格式

输入一个整数 $N$,表示画布大小。

输出格式

输出一个整数表示答案。

由于答案可能很大,所以输出其对 $1000000007$ 取模后的值。

数据范围

$1 \leq N \leq {10}^{7}$。

输入样例:

3

输出样例:

5

样例解释

五种情况如下图所示,颜色只是为了标识不同的积木:

 

解题思路

  这题用状压dp来做,$f \left( {i,j} \right)$表示已经操作完前$i-1$列(前$i-1$列的方格已经被积木全部填满),且第$i$列的状态为$j$的所有方案的集合。可以发现$j$一共又$2^{2}=4$种状态,我们用$00$来表示两个方格都没有积木;$01$表示下面的方格有,上面的方格没有;$10$表示下面的方格没有,上面的方格有;$11$表示两个方格都有积木。

  我们同时规定,对于横跨两列的积木,以这个积木最左边的方块所在的列为它进行操作的列。

  转移状态如下:

  用一个$4 \times 4$的矩阵来表示,如果$a_{ij} = 1$,表示可以从当前列的$i$状态转移到下一列的$j$状态,$a_{ij} = 0$则表示无法转移,根据上图,得到的状态转移矩阵就是

\begin{bmatrix}
1 & 1 & 1 & 1 \\
0 & 0 & 1 & 1 \\
0 & 1 & 0 & 1 \\
1 & 0 & 0 & 0
\end{bmatrix}

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e7 + 10, mod = 1e9 + 7;
 5 
 6 int g[4][4] = {
 7   {1, 1, 1, 1},
 8   {0, 0, 1, 1},
 9   {0, 1, 0, 1},
10   {1, 0, 0, 0}
11 };
12 int f[N][4];
13 
14 int main() {
15     int n;
16     cin >> n;
17     
18     f[1][0] = 1;    // 一开始还没有放任何积木,即第1列的状态为0
19     for (int i = 1; i <= n; i++) {
20         for (int j = 0; j < 4; j++) {       // 枚举第i行的状态
21             for (int k = 0; k < 4; k++) {   // 枚举可以转移到的第i+1行的状态
22                 if (g[j][k]) {              // 如果可以从第i行的j状态转移到第i+1行的k状态
23                     f[i + 1][k] = (f[i + 1][k] + f[i][j]) % mod;    // 转移
24                 }
25             }
26         }
27     }
28     
29     cout << f[n + 1][0];    // 表示前n行已经填满,且第n+1行的状态为0
30     
31     return 0;
32 }

  可以用滚动数组来优化空间,把$f$数组第一维的大小从$N$优化到$2$,AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e7 + 10, mod = 1e9 + 7;
 5 
 6 int g[4][4] = {
 7   {1, 1, 1, 1},
 8   {0, 0, 1, 1},
 9   {0, 1, 0, 1},
10   {1, 0, 0, 0}
11 };
12 int f[2][4];
13 
14 int main() {
15     int n;
16     cin >> n;
17     
18     f[1][0] = 1;
19     for (int i = 1; i <= n; i++) {
20         memset(f[i + 1 & 1], 0, sizeof(f[i + 1 & 1]));
21         for (int j = 0; j < 4; j++) {
22             for (int k = 0; k < 4; k++) {
23                 if (g[j][k]) {
24                     f[i + 1 & 1][k] = (f[i + 1 & 1][k] + f[i & 1][j]) % mod;
25                 }
26             }
27         }
28     }
29     
30     cout << f[n + 1 & 1][0];
31     
32     return 0;
33 }

  当然,也可以从第$i-1$列的状态推到第$i$列的状态,AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e7 + 10, mod = 1e9 + 7;
 5 
 6 int f[2][4];
 7 
 8 int main() {
 9     int n;
10     scanf("%d", &n);
11     
12     f[1][0] = 1;
13     for (int i = 2; i <= n + 1; i++) {
14         memset(f[i & 1], 0, sizeof(f[i & 1]));
15         f[i & 1][0] = (f[i - 1 & 1][0] + f[i - 1 & 1][3]) % mod;
16         f[i & 1][1] = (f[i - 1 & 1][0] + f[i - 1 & 1][2]) % mod;
17         f[i & 1][2] = (f[i - 1 & 1][0] + f[i - 1 & 1][1]) % mod;
18         for (int j = 0; j <= 2; j++) {
19             f[i & 1][3] = (f[i & 1][3] + f[i - 1 & 1][j]) % mod;
20         }
21     }
22     
23     printf("%d", f[n + 1 & 1][0]);
24     
25     return 0;
26 }

 

参考资料

  AcWing 4406. 积木画(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/3799/

标签:10,状态,int,积木,画布,方格
来源: https://www.cnblogs.com/onlyblues/p/16297192.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有