一道关于三角型的题

本题摘自 www.topcoder.com

题目如下:你有一个很多方形格子所组成的矩阵组,一些小方格是黑色的,一些是白色的,而一些是三角型的格子的,三角的格子可以任意90度的旋转也可以打开变成黑色的格子,但任何小格被放置好就不可以再移动

你的任务是找出在这个矩阵组中有多少个潜在的独立的三角型

我们会给你一组数组表示这个矩阵,其中'#' 代表黑色的方块,'/'代码三角型,'.'代表白色的方块

如图 [img]http://pinnacle909-126-com.iteye.com/upload/picture/pic/40648/ae3fe423-c4db-350f-a2ff-dc5e753e49c9.jpg[/img]

将会被表示为{"#//#./#/#",

"####.#/##",

"...../#.#",

".....####"}; 这样的一个矩阵,下面的图列将会分析出这个图里潜在的三角型数
[img]http://pinnacle909-126-com.iteye.com/upload/picture/pic/40650/a7d078a5-16af-3a8b-bad1-08897ffec2c0.jpg[/img]


如图所见,当我们获得这样的一个参数时,有且只有5个独立的三角型图案

以下给出一些类似的参数输入及输出

Constraints
- grid will contain between 1 and 50 elements, inclusive.
- Each element of grid will contain between 1 and 50 characters, inclusive.
- Each element of grid will contain the same number of characters.
- Each character in grid will be '.', '#' or '/'.
Examples
0)
{"//"}

Returns: 10



1)
{"#//#./#/#",
"####.#/##",
"...../#.#",
".....####"}

Returns: 5
This is the example from the statement.


2)
{".#.",
"#/#",
".#."}

Returns: 0



3)
{".../...",
"..///./",
".//#/./"}

Returns: 46



如何来判断一个三角型是否是一个独立的三角型?

首先,一个独立的三角型,必须有2边不是连接着黑色的小方块的,也就是说直角边的2边必须要是空白的小方块,三角型,或者是墙。

可能你会马上这样考虑,那么我遍历这个矩阵,找到所有的三角型,毕竟只有找到三角型才能判断它的2边。但是这样做实际会让第二个问题(组合3角型)变得很麻烦,一个大三角型完全可以包含多个三角型,而且2个大直角三角型,可以组合成为一个等腰三角型。这些都让这个题目的难度增加了很多



请看这张图,恩,很丑:[img]http://pinnacle909-126-com.iteye.com/upload/picture/pic/40646/ee6def1c-b14e-383b-8c71-3b4612cdb45d.jpg[/img]


从左边的图像可以看到1,1这个位置是一个黑色的方块,而1,2这个位置是一个三角型,他们分别属于2个直角三角型,但和在一起变成了一个大三角型,而0,1 和0,2 只有在倒立的情况下才能算一个独立的三角型,如现在所示他们只能贴着1,1这个黑色方块,所以它们无法算做一个三角型

右边的图有一个大三角型但如果你像现在这样放置那2个小的三角型,这这2个图案都不独立的三角型了,如果把那2个小三角型的方向变成 》 大三角型仍然是|— 则他们2 都是三角型,为2个不同的三角型



想了一天大概找到了一些判断的规则和解题的思路,PS:如果你有其他的做法不妨一起讨论下



1 三角型是可以旋转的,这里我们不旋转三角型,而是旋转整个矩阵,然后根据条件2,4找寻符合条件的项,一共旋转3次

2 如何判断一个三角型是一个小三角型,不考虑组合时,很显然,当它的2边为空,墙,三角型时条件成立。所以我们每次都查找三角型格的右侧和下侧,符合要求则成立,如果右侧为三角型还需在跳至规则3判断

3 两个小三角型紧贴在一起的时候有可能合并成为一个占2格的稍大一些的三角型,根据条件1,如果该小三角型的右侧为三角型,并且其下侧的2个格子任何一个都不为黑色方块 ,则成立。之后通过条件1旋转,检查另一个方向是否出现

4 直角大三角型,开始方块不能为空白方块,然后开始检查它所有的斜对角线,如果有空白方块则退出,如果检查到斜对角线全部为三角型方块,并且其不含空白方块,则再检查其2条直角边,跳至规则5

5必须判断大直角三角型的2个直角边,是否有黑色方块紧贴,如果有则该图形不是直角三角型,并跳至规则6继续判断

6 两个大直角三角型组成的三角型,如果一个大直角三角型一边含有黑色方块,那他很可能紧贴着另一个大直角三角型那么我们还需反向判断,看是否存在这样的一个映射三角型,判断参考规则4,5

解决问题的是人,不是程序



  代码如下:

[code]
public class RotatingTriangles {

int n = 0;
int m = 0;
String[] t_grid;

public static void main(String[] args){
String[] test1={"//"};
String[] test2={"#//#./#/#","####.#/##","...../#.#",".....####"};
String[] test3={".#.", "#/#",".#."};
String[] test4={".../...","..///./",".//#/./"};
//should output 10
new RotatingTriangles().count(test1);
//should output 5
new RotatingTriangles().count(test2);
// 0
new RotatingTriangles().count(test3);
//46
new RotatingTriangles().count(test4);
}

public int count(String[] grid) {
t_grid = grid;
int res = 0;
for (int i = 0; i < 4; i++) {
res += countTriangle(t_grid);
t_grid = rotate(t_grid);
}
return res;
}

public int countTriangle(String[] grid) {
t_grid = grid;
n = grid.length;
m = grid[0].length();
int res = 0;

for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
char currentChar = getCV(i, j);
if (currentChar == '/') {
if (j + 1 < m) {
if (i + 1 < n) {
if (getCV(i, j + 1) == '.'&& getCV(i + 1, j) != '#'){ res++;}
if (getCV(i, j + 1) == '/'&& getCV(i + 1, j) != '#'){
res++;
if(getCV(i + 1, j + 1) != '#'){ res++; }
}
} else {
if (getCV(i, j + 1) == '.'){ res++;}
if (getCV(i, j + 1) == '/'){ res+=2;}
}
} else {
if (i + 1 < n) {
if(getCV(i + 1, j) != '#'){res++;}
} else {
res++;
}
}
}

// judge the big T
int a = i + 1, b = j + 1;
boolean whileflag = true;

while (a < n && b < m && whileflag && currentChar != '.') {

char c = checkDiagonal(a,b,i,j,false);

if(c=='.') break;

if (whileflag && c == '/') {
if (i - 1 >=0) {
whileflag = checkHorizontalLine(i-1,j,b);
if (whileflag) {
if(j-1>0){
for (int h = i; h <= a; h++){
if (getCV(h, j - 1) == '#') {
whileflag = false;
break;
}
}
}
}
if(b-j<=j){
if('/'==checkDiagonal(a,b,i,j,true)){
if(checkHorizontalLine(2*j-b,j,j-1))
res++;
}
}
}
if (j - 1 >= 0&&whileflag) {
for (int h = i; h <= a; h++){
if (getCV(h, j - 1) == '#') {
whileflag = false;
break;
}
}
}
if (whileflag) { res++; a++; b++;}
}

if (whileflag && c == '#') {a++; b++;}
}
}
}
return res;
}

public char getCV(int n, int m) {
return t_grid[n].charAt(m);
}

public boolean checkHorizontalLine(int hight,int start,int end){
boolean flag=true;
for (int w = start; w <= end; w++){
if (getCV(hight, w) == '#') {
flag = false;
break;
}
}
return flag;
}

public char checkDiagonal(int a,int b,int i,int j,boolean inverse){
char c = '0';
if(inverse){
for (int x = a-1, y = j; x <= j && y >=a; x++, y--) {
if (c == '0') {
c = getCV(x, y);
} else {
if (getCV(x, y) == '.') {
c='.';
break;
}
c = getCV(x, y)== c ? c : '#';
}
}
}else{
for (int x = a, y = j; x >= i && y <= b; x--, y++) {
if (c == '0') {
c = getCV(x, y);
} else {
if (getCV(x, y) == '.') {
c='.';
break;
}
c = getCV(x, y)== c ? c : '#';
}
}
}
return c;
}

public String[] rotate(String[] grid) {
int h = grid.length;
int w = grid[0].length();
String[] temp = new String[w];

for (int i = 0; i < w; i++) {
String s = "";
for (int j = 0; j < h; j++)
s += grid[j].charAt(i) + "";
temp[w - i - 1] = s;
}
return temp;
}
}
[/code]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值