绝对,非常考耐心,细心的一道题目,这道题目充分的说明我是考虑问题不全面的人
所以现在看来TopCoder的测试数据还都算是比较弱的,真的没有极其变态的,而且TopCoder的题目其实没有超级复杂的,或许是因为我从来没做过第三题吧。
回正题。
这道题目其实一看就知道怎么做,但是就一个字烦
首先你要用FloodFill把所有的Cluster标注出来,这个不难,而且速度很快,时间差不多也就线性的。因为你只需要遍历一遍就可以了。
问题就出在判别一个Cluster的图案以前是否出现过。
首先一个Pattern可以有8种不同的样子,这里我们就不考虑对称的那些特殊情况了,就按一般情况考虑,默认这8种都不相同。
然后你需要把除了已知的一种的剩下七种全部弄出来,其实也不需要全部,不过最差情况你肯定要全弄出来,这种情况发生在出现新的图案的时候。
然后呢,你就跟这些图案去比较,看看是不是相同,这又是一个问题,关键问题,怎么判断是不是一样!
我刚开始的做法就是,记录一个图案的左上角和右下角,也就是minx,miny,maxy,maxy
当我用FloodFill找到了一个新的Cluster的时候,我会在搜索的过程中记录当前这个图案的左上角和右下角
然后就是和已知的每个图案去比较
比较的时候,我把当前的Cluster通过变换生产不同的变种,然后去跟已知的每个图案比较。
我的问题就出在这里了,因为我是用四个角标记一个图案的,那么,很有可能,这个矩形的范围内包括不属于这个图案的点。
例如
0010
1010
0111
1111
很明显,大的那个图案的矩形框左上角是(0,0),右下角是(3,3)
这就把那个不属于他的1包含进去了。
于是,在将两个矩形进行比较的时候,必须要处理这种“噪声”元素。
按照我的这种图案记录方式,我无论怎么判断,似乎都是不行的
于是我只能改策略了,用一个Shape类来记录每一个一致的图案,注意,是精确的记录,不包含那些杂点。
而且只记录第一次出现的,因为在后面陆陆续续出现的图案中,有可能两个一样的图案的矩形框有重叠。
例如
000100000
000100000
000100000
111111100
000101000
000101000
000001000
001111111
000001000
000001000
我们可以看到,这两个“十字架”的矩形框是有重叠的。
我只是精确的记录第一次出现的图案
然后,每次用两个“纯净”的图去比较,也就是说
一是我刚刚FloodFill出来的Cluster,我会用‘2’去标记,注意是字符2
另外一个就是我一致的Shape
这样我就只需要比较他们两个图有标注的地方,如果这些地方有不一致,那么显然不是same的
其实就这么简单的事情,如果写成为代码,我估计5行都用不了。
但是我却写了200多行。
为了能节省时间,旋转90,180,270我是分别写的
1 import java.io.*;
2 /*
3 ID: yanglei4
4 LANG: JAVA
5 TASK:starry
6 */
7 public class starry{
8 public class shape {
9 public int minx,miny,maxx,maxy;
10 public int[][] pattern;
11 shape(int a,int b, int c, int d) {
12 minx = a;
13 miny = b;
14 maxx = c;
15 maxy = d;
16 pattern = new int[maxx- minx + 1][maxy - miny + 1];
17 }
18
19 public int getHeight() {
20 return maxx - minx + 1;
21 }
22
23 public int getWidth() {
24 return maxy - miny + 1;
25 }
26 }
27 shape[] shapes = new shape[126];
28
29 boolean[][] visited;
30 int[][] sky;
31 int H,W;
32 char assignedChar = 'a';
33 int minx,miny,maxx,maxy;
34
35 int count = 0;
36 PrintWriter out;
37 public void floodFill(int x, int y) {
38 visited[x][y] = true;
39 sky[x][y] = '2';
40 if (x - 1 >= 0) {
41 if (visited[x - 1][y] == false && sky[x - 1][y] == 1) {
42 if (x - 1 < minx)
43 minx = x - 1;
44 floodFill(x - 1, y);
45 }
46 if (y - 1 >= 0)
47 if (visited[x - 1][y - 1] == false && sky[x - 1][y - 1] == 1) {
48 if (x - 1 < minx)
49 minx = x - 1;
50 if (y - 1 < miny)
51 miny = y - 1;
52 floodFill(x - 1, y - 1);
53 }
54 if (y + 1 < W)
55 if (visited[x - 1][y + 1] == false && sky[x - 1][y + 1] == 1) {
56 if (x - 1 < minx)
57 minx = x - 1;
58 if (y + 1 > maxy)
59 maxy = y + 1;
60 floodFill(x - 1, y + 1);
61 }
62 }
63 if (y - 1 >= 0)
64 if (visited[x][y - 1] == false && sky[x][y - 1] == 1) {
65 if (y - 1 < miny)
66 miny = y - 1;
67 floodFill(x, y - 1);
68 }
69 if (y + 1 < W)
70 if (visited[x][y + 1] == false && sky[x][y + 1] == 1) {
71 if (y + 1 > maxy)
72 maxy = y + 1;
73 floodFill(x, y + 1);
74 }
75
76 if (x + 1 < H) {
77 if (visited[x + 1][y] == false && sky[x + 1][y] == 1) {
78 if (x + 1 > maxx)
79 maxx = x + 1;
80 floodFill(x + 1, y);
81 }
82 if (y - 1>= 0)
83 if (visited[x + 1][y - 1] == false && sky[x + 1][y - 1] == 1) {
84 if (x + 1 > maxx)
85 maxx = x + 1;
86 if (y - 1 < miny)
87 miny = y - 1;
88 floodFill(x + 1, y - 1);
89 }
90 if (y + 1 < W)
91 if (visited[x + 1][y + 1] == false && sky[x + 1][y + 1] == 1) {
92 if (x + 1 > maxx)
93 maxx = x + 1;
94 if (y + 1 > maxy)
95 maxy = y + 1;
96 floodFill(x + 1, y + 1);
97 }
98 }
99 }
100
101 public int[][] R90(int[][] source, int height, int width) {
102 int[][] result = new int[width][height];
103
104 for (int i = 0; i < height; i++)
105 for (int j = 0; j < width; j++)
106 result[j][height - i - 1] = source[i][j];
107
108 return result;
109 }
110
111 public int[][] R180(int[][] source, int height, int width) {
112 int[][] result = new int[height][width];
113
114 for (int i = 0; i < height; i++)
115 for (int j = 0; j < width; j++)
116 result[height - i - 1][width - j - 1] = source[i][j];
117
118 return result;
119 }
120
121 public int[][] L90(int[][] source, int height, int width) {
122 int[][] result = new int[width][height];
123
124 for (int i = 0; i < height; i++)
125 for (int j = 0; j < width; j++)
126 result[width - j - 1][i] = source[i][j];
127
128 return result;
129 }
130
131 public int[][] Flip(int[][] source, int height, int width) {
132 int[][] result = new int[height][width];
133
134 for (int i = 0; i < height; i++)
135 for (int j = 0; j < width; j++)
136 result[i][j] = source[i][width - j - 1];
137 return result;
138 }
139
140 public boolean isSame(int[][] source, int[][] dest, int height, int width, int pattern) {
141 for (int i = 0; i < height; i++)
142 for (int j = 0; j < width; j++) {
143 if ((dest[i][j] == pattern + 1 && source[i][j] != '2') || (dest[i][j] != pattern + 1 && source[i][j] == '2')) return false;
144 }
145 return true;
146 }
147
148 public int checkSame() {
149
150 int height = maxx - minx + 1;
151 int width = maxy - miny + 1;
152
153 int[][] dest = new int[height][width];
154
155 for (int i = minx; i <= maxx; i++)
156 for (int j = miny; j <= maxy; j++)
157 if (sky[i][j] == '2')
158 dest[i - minx][j - miny] = sky[i][j];
159
160
161 boolean same = false;
162 int i = 0;
163 for (i = 0; i < count; i++) {
164 //copy the shape
165 int[][] source = new int[shapes[i].getHeight()][shapes[i].getWidth()];
166 for (int a = 0; a < shapes[i].getHeight(); a++)
167 for (int b = 0; b < shapes[i].getWidth(); b++)
168 source[a][b] = shapes[i].pattern[a][b];
169
170 if(shapes[i].getHeight() == height && shapes[i].getWidth() == width) {
171 if (isSame(dest,source,height,width,i) == true ||
172 isSame(Flip(dest, height, width),source,height,width,i) == true ||
173 isSame(R180(dest,height,width),source, height,width,i) == true ||
174 isSame( Flip(R180(dest,height,width), height, width),source, height,width,i) == true) {
175 same = true;
176 break;
177 }
178
179 }
180 if (shapes[i].getWidth() == height && shapes[i].getHeight() == width) {
181 if (isSame(R90(dest,height,width), source, width, height,i) == true ||
182 isSame(L90(dest,height,width), source, width, height,i) == true ||
183 isSame(Flip(R90(dest,height,width), width, height), source, width,height,i) == true ||
184 isSame(Flip(L90(dest,height,width), width, height), source, width,height,i) == true) {
185 same = true;
186 break;
187 }
188 }
189 }
190
191 if (!same)
192 {
193 shapes[count] = new shape(minx,miny,maxx,maxy);
194 for (int a = 0; a < height; a++)
195 for (int b = 0; b < width; b++)
196 if (dest[a][b] == '2')
197 shapes[i].pattern[a][b] = count + 1;
198 count++;
199 return 0;
200 }
201 else
202 return i + 1;
203 }
204 public void done() throws IOException {
205 BufferedReader f = new BufferedReader(new FileReader("starry.in"));
206 out = new PrintWriter(new BufferedWriter(new FileWriter("starry.out")));
207 W = Integer.parseInt(f.readLine());
208 H = Integer.parseInt(f.readLine());
209
210 sky = new int[H][W];
211 visited = new boolean[H][W];
212
213 for (int i = 0; i < H; i++) {
214 String temp = f.readLine();
215 int len = temp.length();
216 for (int j = 0; j < len; j++)
217 sky[i][j] = temp.charAt(j) - '0';
218 }
219 for (int i = 0; i < H; i++)
220 for (int j = 0; j < W; j++)
221 if (visited[i][j] == false && sky[i][j] == 1) {
222 minx = maxx = i;
223 miny = maxy = j;
224 floodFill(i,j);
225 //System.out.println("[" + minx + "," + miny + "][" + maxx + "," + maxy + "]");
226 int temp = checkSame();
227 if (temp == 0)
228 temp = count;
229 for (int a = minx; a <= maxx; a++)
230 for (int b = miny; b <= maxy; b++)
231 if (sky[a][b] == '2') sky[a][b] = temp;
232 }
233 print();
234 out.close();
235 }
236
237 public void print() {
238 for (int i = 0; i < H; i++) {
239 for (int j = 0; j < W; j++)
240 if (sky[i][j] != 0)
241 out.print((char)(sky[i][j] + 'a' - 1));
242 else
243 out.print("0");
244 out.println();
245 }
246 }
247 public static void main(String[] args) throws IOException {
248 starry t = new starry();
249 t.done();
250 System.exit(0);
251 }
252 }