首页 > 其他 > 详细

洛谷 P1924 poj 1038

时间:2018-07-08 10:09:21      阅读:201      评论:0      收藏:0      [点我收藏+]

Description:

  给你一个n * m的方格纸,有一些格子无法被覆盖,然后用2*3的格子覆盖这个方格纸,问你最多能放多少个格子

神级状压

为了弄清楚这道题翻了无数篇解题报告,最后终于搞明白了

用三进制表示每行的状态,要表示出第j个,第j-1个

比如对于第i行第j列。 如果j列,j列也是空的则用0表示,j 列不能放用2表示,剩下的(仅j - 1列不能放)用1表示

然后深搜进行转移

干讲没意思,具体看注释,写的很清楚了(AC代码是poj的,稍微改一下输入输出就是洛谷的)

技术分享图片
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int N = 59050;
 6 /*pre表示你枚举的上一个状态,now表示你现在枚举的状态*/
 7 int dp[2][N], mp[160][15], pre[12], now[12], n, m, d, cur;
 8 int base[] = {0,1,3,9,27,81,243,729,2187,6561,19683,59049};
 9 void init(){
10     memset(mp, 0, sizeof(mp));
11     memset(dp, -1, sizeof(dp));
12 }
13 /*3进制转10进制*/
14 int trans(int *t){
15     int ans = 0;
16     for(int i = 1; i <= m; i++)
17       ans += t[i] * base[i];
18     return ans;
19 }
20 /*10进制转3进制*/
21 void chan(int t, int *p){
22     for(int i = 1; i <= m; i++)
23       p[i] = t % 3, t /= 3;
24     return ;
25 }
26 /*i为当前行,j为当前状态,cnt为格子数目,tmp为当前压缩后整行状态*/
27 void dfs(int i, int j, int cnt, int tmp){
28     int k;
29     dp[i & 1][tmp] = max(dp[i & 1][tmp], cnt);
30     if(j >= m) return ;
31     /*放上3行2列的格子
32       如果该层状态和前一层的状态都允许 那么就放上格子继续搜下去*/
33     if(!pre[j] && !pre[j + 1] && !now[j] && !now[j + 1]){
34         now[j] = now[j + 1] = 2;  //放格子之后状态就都是2了
35         k = trans(now); dfs(i, j + 2, cnt + 1, k);//因为两格都被覆盖,跳过去搜
36         now[j] = now[j + 1] = 0;  //回溯
37     }
38     /*放上2行3列的格子
39      这个就只跟你当前的状态有关了*/
40     if(j < m - 1 && !now[j] && !now[j + 1] && !now[j + 2]){
41         now[j] = now[j + 1] = now[j + 2] = 2; //同样修改 搜下去 回溯
42         k = trans(now);  dfs(i, j + 3, cnt + 1, k);
43         now[j] = now[j + 1] = now[j + 2] = 0;
44     }
45     dfs(i, j + 1, cnt, tmp);
46     return ;
47 }
48 int main(){
49     int T, x, y;
50     scanf("%d", &T);
51     while(T--){
52         init();
53         scanf("%d%d%d", &n, &m, &d);
54         for(int i = 1; i <= d; i++){
55             scanf("%d%d", &x, &y);
56             mp[x][y] = 1;
57         }
58         for(int i = 1; i <= m; i++)
59           pre[i] = 2;
60         int tmp = trans(pre);
61         dp[0][tmp] = 0;  //对于第0行来说,只有啥都不能放这一种状态 将该状态价值为0
62         for(int i = 1; i <= n; i++){
63             memset(dp[i & 1], -1, sizeof(dp[i & 1]));  //初始化本次要用的dp数组
64             for(int j = 0; j < base[m + 1]; j++){  //枚举上一行的状态
65                 /* 如果上一行的状态dp数组为-1,说明上一层的该状态根本达不到,那么就不能用来转移*/
66                 if(dp[i + 1 & 1][j] == -1) continue;
67                 chan(j, pre); //将上一层的状态转换成3进制
68                 for(int k = 1; k <= m; k++)  //k为j状态往后移一格的状态
69                   if(mp[i][k]) now[k] = 2; //如果此时第k位无法覆盖,那么就为状态为2
70                 /*不然,2状态变为1状态,其余为0(根据状态的定义就可以得出)*/
71                   else now[k] = max(pre[k] - 1, 0); 
72                 cur = dp[i + 1 & 1][j];  //cur表示上一层该状态达到的最大价值
73                 dfs(i, 1, cur, trans(now)); //dfs转移 因为第一格前为第0格不能放,所以状态为1
74             }
75         }
76         int ans = 0;
77         for(int i = 0; i < base[m + 1]; i++)
78           ans = max(ans, dp[n & 1][i]);
79         printf("%d\n", ans);
80     }
81     return 0;
82 }
View Code

 

洛谷 P1924 poj 1038

原文:https://www.cnblogs.com/Rorshach/p/9279058.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!