chip

1、芯片(chip.pas/cpp)

【问题描述】
企鹅集成电路公司生产了一种大小为 2×3的芯片。每块芯片是从一块大小为N×M的硅
片上切下来的,但由于原材料纯度问题,因而有若干的单位正方形并不能作为芯片的一部分。
企鹅集成电路公司想要知道,给定一块 N×M大小的硅片和坏掉的单位正方形的位置,最
多能使用这块硅片生产多少芯片?

【输入格式】
输入的第一行由一个正整数 D 构成,表示硅片的个数。
随后跟着 D 个数据,每个数据第一行包含三个整数 N,M,K,分别表示硅片的长和宽,
以及硅片坏掉的单位正方形个数。
接下 K 行,每行两个整数 X , Y ,表示单位正方形的坐标。
注:左上角的单位正方形用 (1,1) 表示,右下角的单位正方形用 (N,M) 表示。

【输出格式】
共 D 行,每行一个整数,即最多能切出多少个芯片。

【输入样例】

1
6 6 5
1 4
4 6
2 2
3 6
6 4

【输出样例】
3

【数据范围】
对于 10% 的数据,K=0;
对于另 外10%的数据,1≤M≤5,K≤1;
对于40%的数据,1≤M≤8;
最后一个测试点,空间限制8MB,其余限制64MB。
对于所有数据,1≤D≤5,1≤N≤150,1≤M≤10,0≤K≤M。

好。看一看就发现是状压DP,不会写,写了个搜索拿40分,稳的很。

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 const int N = 160;
  5 
  6 bool vis[N][12];
  7 int ans, n, m;
  8 
  9 inline void read(int &x) {
 10     x = 0;
 11     char c = getchar();
 12     while(c > '9' || c < '0') {
 13         c = getchar();
 14     }
 15     while(c >= '0' && c <= '9') {
 16         x = (x << 3) + (x << 1) + c - 48;
 17         c = getchar();
 18     }
 19     return;
 20 }
 21 
 22 inline int getmax(int x, int y) {
 23     int tp = 0;
 24     for(int i = x; i <= n; i++) {
 25         for(int j = (i == x) ? y : 1; j <= m; j++) {
 26             if(!vis[i][j]) {
 27                 tp++;
 28             }
 29         }
 30     }
 31     return tp / 6;
 32 }
 33 
 34 inline bool valid1(int x, int y) {
 35     if(x + 2 > n || y + 1 > m) {
 36         return 0;
 37     }
 38     for(int i = x; i <= x + 2; i++) {
 39         for(int j = y; j <= y + 1; j++) {
 40             if(vis[i][j]) {
 41                 return 0;
 42             }
 43         }
 44     }
 45     return 1;
 46 }
 47 
 48 inline bool valid2(int x, int y) {
 49     if(x + 1 > n || y + 2 > m) {
 50         return 0;
 51     }
 52     for(int i = x; i <= x + 1; i++) {
 53         for(int j = y; j <= y + 2; j++) {
 54             if(vis[i][j]) {
 55                 return 0;
 56             }
 57         }
 58     }
 59     return 1;
 60 }
 61 
 62 void DFS(int k, int x, int y) {
 63     if(k > ans) {
 64         ans = k;
 65     }
 66     if(y > m) {
 67         y = 1;
 68         x++;
 69     }
 70     if(x > n) {
 71         return;
 72     }
 73     int t = getmax(x, y);
 74     if(k + t <= ans) {
 75         return;
 76     }
 77     for(int i = x; i <= n; i++) {
 78         for(int j = (i == x) ? y : 1; j <= m; j++) {
 79             if(valid1(i, j)) {
 80                 for(int a = i; a <= i + 2; a++) {
 81                     vis[a][j] = 1;
 82                     vis[a][j + 1] = 1;
 83                 }
 84                 DFS(k + 1, i, j + 1);
 85                 for(int a = i; a <= i + 2; a++) {
 86                     vis[a][j] = 0;
 87                     vis[a][j + 1] = 0;
 88                 }
 89             }
 90             if(valid2(i, j)) {
 91                 for(int b = j; b <= j + 2; b++) {
 92                     vis[i][b] = 1;
 93                     vis[i + 1][b] = 1;
 94                 }
 95                 DFS(k + 1, i, j + 1);
 96                 for(int b = j; b <= j + 2; b++) {
 97                     vis[i][b] = 0;
 98                     vis[i + 1][b] = 0;
 99                 }
100             }
101         }
102     }
103     return;
104 }
105 
106 int main() {
107     freopen("chip.in", "r", stdin);
108     freopen("chip_bf.out", "w", stdout);
109     int T;
110     read(T);
111     while(T--) {
112         int k;
113         ans = 0;
114         memset(vis, 0, sizeof(vis));
115         read(n); read(m); read(k);
116         for(int i = 1, x, y; i <= k; i++) {
117             read(x); read(y);
118             vis[x][y] = 1;
119         }
120 
121         DFS(0, 1, 1);
122 
123         printf("%d\n", ans);
124     }
125 
126     return 0;
127 }
40分搜索

因为我用了一些奇淫技巧剪枝,是搜索中最稳的。

 

正解:轮廓线DP。

因为最高只有3,那么我们用三进制。

0 表示第 i 行与 i - 1 行皆为空。

1 表示第 i 行为空,i - 1 行被占用。

2 表示第 i 行被占用,i - 1任意。

转移的时候:枚举 i - 1 行的状态 j ,然后根据 j 推出什么都不放时的第 i 行的状态(即每一位 - 1)

考虑第 i 行每个位置放某个方格的左下角。

DFS转移:从第 i 行第一格开始转移。有三种选择:

放一个竖着的,DFS第三格

放一个横着的,DFS第四格

不放,DFS第二格

以此类推。

滚动数组优化:研究转移代码,发现只用到了 i - 1 行

开两个,用 i & 1

三进制状压:zip和unzip函数,指针的用法:

 1 inline void unzip(int x, int *a) {
 2     for(int i = m - 1; i >= 0; i--) {
 3         a[i] = x % 3;
 4         x /= 3;
 5     }
 6     return;
 7 }
 8 inline int zip(int *a) {
 9     int x = 0;
10     for(int i = 0; i < m; i++) {
11         x = x * 3 + a[i];
12     }
13     return x;
14 }
三进制状压

乱七八糟的知识点...

看代码看代码。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 const int N = 160, M = 15;
 6 
 7 int tri[M], f[N][60000], pre[M], now[M];
 8 int m, n, G[N][M];
 9 
10 inline void unzip(int x, int *a) {
11     for(int i = m - 1; i >= 0; i--) {
12         a[i] = x % 3;
13         x /= 3;
14     }
15     return;
16 }
17 inline int zip(int *a) {
18     int x = 0;
19     for(int i = 0; i < m; i++) {
20         x = x * 3 + a[i];
21     }
22     return x;
23 }
24 
25 void DFS(int x, int y, int last_ans, int now_sta) {
26     f[x][now_sta] = std::max(f[x][now_sta], last_ans); /// error : down
27     if(y + 1 >= m) {
28         return;
29     }                                                  /// here
30     DFS(x, y + 1, last_ans, now_sta);
31     if(!now[y] && !now[y + 1] && !pre[y] && !pre[y + 1]) {
32         now[y] = now[y + 1] = 2;
33         int temp = zip(now);
34         DFS(x, y + 2, last_ans + 1, temp);
35         now[y] = now[y + 1] = 0;
36     }
37     if(y + 2 < m && !now[y] && !now[y + 1] && !now[y + 2]) {
38         now[y] = now[y + 1] = now[y + 2] = 2;
39         int temp = zip(now);
40         DFS(x, y + 3, last_ans + 1, temp);
41         now[y] = now[y + 1] = now[y + 2] = 0;
42     }
43     return;
44 }
45 
46 int main() {
47     freopen("chip.in", "r", stdin);
48     freopen("chip.out", "w", stdout);
49     tri[0] = 1;
50     for(int i = 1; i < 12; i++) {
51         tri[i] = tri[i - 1] * 3;
52     }
53     int T;
54     scanf("%d", &T);
55     while(T--) {
56         int k;
57         scanf("%d%d%d", &n, &m, &k);
58         memset(f, -1, sizeof(f));
59         memset(G, 0, sizeof(G));
60         int x, y;
61         while(k--) {
62             scanf("%d%d", &x, &y);
63             G[x][y - 1] = 1;
64         }
65         for(int i = 0; i < m; i++) {
66             pre[i] = G[1][i] + 1; /// error : G[1][m]
67         }
68         int temp = zip(pre);
69         f[1][temp] = 0;
70         for(int i = 2; i <= n; i++) { /// hang
71             for(int j = 0; j < tri[m]; j++) { /// i - 1 : state j
72                 if(f[i - 1][j] == -1) {
73                     continue;
74                 }
75                 unzip(j, pre);
76                 for(int k = 0; k < m; k++) { /// get i state
77                     if(G[i][k]) {
78                         now[k] = 2; /// error : now[i]
79                     }
80                     else {
81                         now[k] = std::max(pre[k] - 1, 0);/// error : now[i] pre[i]
82                     }
83                 }
84                 temp = zip(now);
85                 DFS(i, 0, f[i - 1][j], temp); /// DFS trans
86             }
87         }
88         int ans = 0;
89         for(int i = 0; i < tri[m]; i++) { /// get ans
90             ans = std::max(ans, f[n][i]);
91         }
92         printf("%d\n", ans);
93     }
94 
95     return 0;
96 }
普通
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 const int N = 160, M = 15;
 6 
 7 int tri[M], f[2][60000], pre[M], now[M];
 8 int m, n, G[N][M];
 9 
10 inline void unzip(int x, int *a) {
11     for(int i = m - 1; i >= 0; i--) {
12         a[i] = x % 3;
13         x /= 3;
14     }
15     return;
16 }
17 inline int zip(int *a) {
18     int x = 0;
19     for(int i = 0; i < m; i++) {
20         x = x * 3 + a[i];
21     }
22     return x;
23 }
24 
25 void DFS(int x, int y, int last_ans, int now_sta) {
26     f[x & 1][now_sta] = std::max(f[x & 1][now_sta], last_ans); /// error : down
27     if(y + 1 >= m) {
28         return;
29     }                                                  /// here
30     DFS(x, y + 1, last_ans, now_sta);
31     if(!now[y] && !now[y + 1] && !pre[y] && !pre[y + 1]) {
32         now[y] = now[y + 1] = 2;
33         int temp = zip(now);
34         DFS(x, y + 2, last_ans + 1, temp);
35         now[y] = now[y + 1] = 0;
36     }
37     if(y + 2 < m && !now[y] && !now[y + 1] && !now[y + 2]) {
38         now[y] = now[y + 1] = now[y + 2] = 2;
39         int temp = zip(now);
40         DFS(x, y + 3, last_ans + 1, temp);
41         now[y] = now[y + 1] = now[y + 2] = 0;
42     }
43     return;
44 }
45 
46 int main() {
47     freopen("chip.in", "r", stdin);
48     freopen("chip_bf.out", "w", stdout);
49     tri[0] = 1;
50     for(int i = 1; i < 12; i++) {
51         tri[i] = tri[i - 1] * 3;
52     }
53     int T;
54     scanf("%d", &T);
55     while(T--) {
56         int k;
57         scanf("%d%d%d", &n, &m, &k);
58         memset(G, 0, sizeof(G));
59         memset(f, -1, sizeof(f));
60         int x, y;
61         while(k--) {
62             scanf("%d%d", &x, &y);
63             G[x][y - 1] = 1;
64         }
65         for(int i = 0; i < m; i++) {
66             pre[i] = G[1][i] + 1; /// error : G[1][m]
67         }
68         int temp = zip(pre);
69         f[1][temp] = 0;
70         for(int i = 2; i <= n; i++) { /// hang
71             for(int j = 0; j < tri[m]; j++) {
72                 f[i & 1][j] = -1;
73             }
74             for(int j = 0; j < tri[m]; j++) { /// i - 1 : state j
75                 if(f[(i + 1) & 1][j] == -1) {
76                     continue;
77                 }
78                 unzip(j, pre);
79                 for(int k = 0; k < m; k++) { /// get i state
80                     if(G[i][k]) {
81                         now[k] = 2; /// error : now[i]
82                     }
83                     else {
84                         now[k] = std::max(pre[k] - 1, 0);/// error : now[i] pre[i]
85                     }
86                 }
87                 temp = zip(now);
88                 DFS(i, 0, f[(i + 1) & 1][j], temp); /// DFS trans
89             }
90         }
91         int ans = 0;
92         for(int i = 0; i < tri[m]; i++) { /// get ans
93             ans = std::max(ans, f[n & 1][i]);
94         }
95         printf("%d\n", ans);
96     }
97 
98     return 0;
99 }
滚动数组优化空间

这几个错调的真不容易啊......

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int tri[15] = {0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049};
 5 int n, m, k, dp[2][59049], pre[15], now[15];  //滚动数组来记录
 6 bool g[155][15];
 7 int getTen(int *a)//把一个用数组表示的状态转化为一个10进制整数
 8 {
 9         int ans = 0;
10         for(int i = 1; i <= m; ++i)
11                 ans += a[i]*tri[i];
12         return ans;
13 }
14 void getTri(int v, int *a)//把一个整数转化为一个数组来表示状态
15 {
16         for(int i = 1; i <= m; ++i) {
17                 a[i] = v%3;
18                 v /= 3;
19         }
20 }
21 void dfs(int x, int y, int last, int key)
22 {
23         int k;
24         dp[x&1][key] = max(dp[x&1][key], last);
25         if(y >= m) return;
26         if(!pre[y] && !pre[y+1] && !now[y] && !now[y+1]) {//竖着切割
27                 now[y] = now[y+1] = 2;
28                 k = getTen(now);
29                 dfs(x, y+2, last+1, k);
30                 now[y] = now[y+1] = 0;
31         }
32         if(y<m-1 && !now[y] && !now[y+1] && !now[y+2]) {  //横着切割
33  
34                 now[y] = now[y+1] = now[y+2] = 2;
35                 k = getTen(now);
36                 dfs(x, y+3, last+1, k);
37                 now[y] = now[y+1] = now[y+2] = 0;
38         }
39         dfs(x, y+1, last, key); //不做改动,直接下一行
40 }
41 int main()
42 {
43     freopen("chip.in","r",stdin);
44     freopen("chip.out","w",stdout);
45         int t, a, b, tmp;
46         scanf("%d", &t);
47         while(t--) {
48                 scanf("%d%d%d", &n, &m, &k);
49                 memset(g, 0, sizeof(g));
50                 for(int i = 0; i < tri[m+1]; ++i) dp[1][i] = -1;
51                 for(int i = 0; i < k; ++i) {
52                         scanf("%d%d", &a, &b);
53                         g[a][b] = 1;
54                 }
55                 for(int i = 1; i <= m; ++i)
56                         pre[i] = g[1][i]+1; //设置第一行的状态,第0行的方块全部视为不可用
57                 tmp = getTen(pre);
58                 dp[1][tmp] = 0;
59                 for(int i = 2; i <= n; ++i) {
60                         for(int j = 0; j < tri[m+1]; ++j) dp[i&1][j] = -1;
61                         for(int j = 0; j < tri[m+1]; ++j) {
62                                 if(dp[(i+1)&1][j] == -1) continue; //跳过不可能的子状态
63                                 getTri(j, pre);
64                                 for(int l = 1; l <= m; ++l)  //根据上一行的状态得到本行的状态
65                                         if(g[i][l]) now[l] = 2;
66                                         else now[l] = max(pre[l]-1, 0);
67                                 tmp = getTen(now);
68                                 dfs(i, 1, dp[(i+1)&1][j], tmp);
69                         }
70                 }
71                 int ans = 0;
72                 for(int i = 0; i < tri[m+1]; ++i)
73                         ans = max(ans, dp[n&1][i]);
74                 printf("%d\n", ans);
75         }
76         return 0;
77 }
std

 

 

posted @ 2018-07-10 17:46  huyufeifei  阅读(683)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜