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 }
因为我用了一些奇淫技巧剪枝,是搜索中最稳的。
正解:轮廓线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 }