chip

一、芯片(chip.pas/cpp)

【問題描述】
企鵝集成電路公司生產了一種大小爲 2×3的芯片。每塊芯片是從一塊大小爲N×M的硅
片上切下來的,但因爲原材料純度問題,於是有若干的單位正方形並不能做爲芯片的一部分。
企鵝集成電路公司想要知道,給定一塊 N×M大小的硅片和壞掉的單位正方形的位置,最
多能使用這塊硅片生產多少芯片?

【輸入格式】
輸入的第一行由一個正整數 D 構成,表示硅片的個數。
隨後跟着 D 個數據,每一個數據第一行包含三個整數 N,M,K,分別表示硅片的長和寬,
以及硅片壞掉的單位正方形個數。
接下 K 行,每行兩個整數 X , Y ,表示單位正方形的座標。
注:左上角的單位正方形用 (1,1) 表示,右下角的單位正方形用 (N,M) 表示。

【輸出格式】
共 D 行,每行一個整數,即最多能切出多少個芯片。

【輸入樣例】 c++

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。
ide

好。看一看就發現是狀壓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,那麼咱們用三進制。spa

0 表示第 i 行與 i - 1 行皆爲空。指針

1 表示第 i 行爲空,i - 1 行被佔用。code

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

轉移的時候:枚舉 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
相關文章
相關標籤/搜索