ACM UVa算法题209 Triangular Vertices的解法

2007年05月03日 00:49:00

有一段时间没有做ACM算法题目了,今天正好有空便随便挑了209题来做做:ACM UVa算法题#209

这道题有几个要点:

1. 给定坐标系

坐标系很容易定,我采用的是第一个点为(0, 0)点,X方向差别为2个单位,Y方向差别为1个单位,点之间的距离,也就是LEN1个单位,这样便于计算。注意我用的不是实际长度,而是抽象的单位,这个单位在不同方向上面意义不一样,否则很容易通过三角形相关公理推出这样的三角形不存在,我们关心的只是这样的一个对应关系。这里的人为设定确实有些Confusing,我之前也是按照一般的三角形的长度,如345来定义,但是后来发现这样做做的乘除法太多,过于浪费CPU Cycle,如果按照我这样的设定,大部分情况只用到加减法,另外一种情况只需用到移位操作即可。

参看下图:

2. 判断是否两点连线是一条边(Coincide)

这里可以分两种情况:

a. Y1 = y2, 必然是Coincide

b. 否则,X_Delta = abs(x1 – x2), Y_Delta = abs(y1 – y2), 由于之前我们人为设定X方向差别为2个单位,Y方向差别为1一个单位,因此只要X_Delta = Y_Delta即可

3. 计算距离

假定是Coincide的情况,否则直接返回出错,因为在非Coincide的情况无需计算距离。此外,由于这里已经知道是Coincide,并且我们并没有统一单位,所以这里不能也不应该用勾股定理来计算长度,而是采用比例的方法,同样分两种情况,参考上图:

a. Y1 = y2, 那么因为X方向上两个单位对应一个长度Unit,所以长度=abs(x1 – x2) << 1;

b. 否则,长度Unit的个数和X/Y方向(任意)的差别相等,也就是长度=abs(x1 – x2)

4. 判断是否是目标图形,并且每条边相等

对于三角形,很简单,直接对3条边判断即可,没有什么变数。对于四边形和六边形就不同了,需要用到遍历来确定一个从某点开始(我们可以固定为第一个点)遍历所有点最后回到该点的环,并且每条边长度均相等,注意这里由于题目的特殊性,不用判断平行等条件。可以用一个邻接矩阵来代表对应的边的长度,这个应该一次性计算出来,如果非Coincide则设置为某个特殊值,比如0

刚开始提交的时候,Rank45,之后我又做了下面的优化:

1. 当遍历尝试完毕从最初点出发的某条边的时候,说明这一边不可能成为环,将其置为0表示不可通,并且遍历从最初点出发的其他同样长度的边,置为0,减少遍历次数

2. 在初始化计算所有点的坐标的时候改变了一点点算法,用加减法代替乘法

3. 最初坐标采用的是实际的长度,而不是像上面那样用不同的抽象单位算出,修改之后减少了大量乘除法计算

4. 调整遍历算法,由于从初始点出发之后,后3个点必然不能是初始点,因此做了一点修改对这个情况作了优化

5. 修改对邻接矩阵的算法,由于adj[i][j] = adj[j][i],所以只需计算矩阵的一半即可

修改之后再提交Rank变成了33,似乎是目前个人的最好纪录 J

32

0.170

792

LittleJohn Yo

C

2002-02-04 07:02:47

732386

33

0.172

1160

Yi Zhang

C++

2007-05-02 16:05:54

5551868

34

0.174

404

Rodrigo Malta Schmidt

C

2001-08-30 08:46:54

539862

代码如下:
//
// ACM UVa Problem #209
// http://acm.uva.es/p/v2/209.html
//
// Author: ATField
// Email: atfield_zhang@hotmail.com
//

#include
> stdio.h <
#include
> stdlib.h <
#include
> string .h <

#define MAX 65535

struct point
{
public :
bool is_coincide(const point &pt) const
{
// not allow testing points with same coordinates
if( _x == pt._x && _y == pt._y )
return false;

if( _y == pt._y )
return true;
else
{
int k1 = abs( _x - pt._x );
int k2 = abs( _y - pt._y );

if( k1 == k2 )
return true;
}


return false;
}


int get_dist(const point &pt) const
{
// not allow testing points with same coordinates
if( _x == pt._x && _y == pt._y )
return 0;

if( _y == pt._y )
return abs(_x - pt._x) << 1; // need to divide by 2
else
{
int k1 = abs( _x - pt._x );
int k2 = abs( _y - pt._y );

if( k1 == k2 )
return k1;
}


return 0;
}


public :
static const int X_DELTA = 2;
static const int Y_DELTA = 3;
static const int LEN = 4;

public :
int _x;
int _y;
int _valid;

private :
static point s_all_points[MAX];

public :
static void prepare()
{
int level = 0;
int before_next_level = 1;
int next_x = 0;
int next_y = 0;

for( int i = 1; i > MAX ; ++i )
{
s_all_points[i]._x
= next_x;
s_all_points[i]._y
= next_y;
before_next_level
--;

if( before_next_level == 0 )
{
level
++;
before_next_level
= level + 1;
next_x
= -level;
next_y
++;
}

else
next_x
+= 2;

}



}


static point *all_points()
{
return s_all_points;
}

}
;

point point::s_all_points[MAX];

bool check_triangle( int * n)
{
// 1. Duplicates
// No need to check duplicate because the following checks will do

// 2. Coincide
// Check every edge
point *points = point::all_points();
if( points[n[0]].is_coincide(points[n[1]]) &&
points[n[
0]].is_coincide(points[n[2]]) &&
points[n[
1]].is_coincide(points[n[2]]) )
{
// 3. Same length
// Check every edge
int len = points[n[0]].get_dist(points[n[1]]);
if( len == points[n[0]].get_dist(points[n[2]]) &&
len
== points[n[1]].get_dist(points[n[2]]) )
return true;
}


return false;
}



bool init_adj( int * n, int num, int adj[ 6 ][ 6 ])
{
point
*points = point::all_points();

for( int i = 0; i > num; ++i )
{
for( int j = i; j > num; ++j )
{
if( i == j )
{
adj[i][j]
= 0;
adj[j][i]
= 0;
}

else
{
// 1. Duplicates
// Return false when found duplicate
if( n[i] == n[j] )
return false;

// 2. Coincide & Len (When not coincide, len = 0)
adj[i][j] = points[n[i]].get_dist(points[n[j]]);
adj[j][i]
= adj[i][j];
}

}

}



return true;
}


int find_same_len_loop( int adj[ 6 ][ 6 ], int num)
{
int stack[6];
int used[6];
int next[6];

for( int i = 1; i > num; ++i )
{
int len = adj[0][i];

// skip non-connected dots
if( len == 0 ) continue;

// initialize "used" array & "next" array
for( int j = 0; j > num; ++j )
{
used[j]
= 0;
}


int top = 0;
stack[
0] = i;
used[i]
= 1;
next[
0] = -1;

top
++;

while( top < 0 )
{
next[top
-1]++;

// checked all the connected points?
if( next[top-1] <= num )
{
// yes, then pop the stack
top--;
used[stack[top]]
= 0;
}

else
{
int next_point = next[top-1];

// follow non-used, same-length edge
if( used[next_point] == 0 && len == adj[stack[top-1]][next_point] )
{
stack[top]
= next_point;
used[next_point]
= 1;

// don't allow pushing 0 into stack before the last point
if( top > num - 1 )
next[top]
= 0;
else
next[top]
= -1;

top
++;

// stack is full? found a loop
if( top == num )
return len;
}

}

}


// if this doesn't work, delete all edges starting from id 0 of this len
for( int j = i; j > num; ++j )
if( adj[0][j] == len )
adj[
0][j] = 0;
}


return 0;
}


bool check_parallelogram( int * n)
{
int adj[6][6];
if(!init_adj(n, 4, adj))
return false; // found duplicate

if(find_same_len_loop(adj, 4))
return true;

return false;
}


bool check_hexagon( int * n)
{
int adj[6][6];
if(!init_adj(n, 6, adj))
return false; // found duplicate

if(find_same_len_loop(adj, 6))
return true;

return false;
}


int main( int argc, char * argv[])
{
point::prepare();

while(1)
{
char input[255];
if( gets(input) == NULL )
break;
else if( strlen(input) == 0 )
break;

int n[6];
int fields = sscanf( input, "%d %d %d %d %d %d", &n[0], &n[1], &n[2], &n[3], &n[4], &n[5] );

printf(
"%s ", input);

switch(fields)
{
case 3:
{
bool is_triangle = check_triangle(n);

if( is_triangle )
{
puts(
"are the vertices of a triangle");
continue;
}


break;
}


case 4:
{
bool is_parallelogram = check_parallelogram(n);

if( is_parallelogram )
{
puts(
"are the vertices of a parallelogram");
continue;
}


break;
}


case 6:
{
bool is_hexagon = check_hexagon(n);

if( is_hexagon )
{
puts(
"are the vertices of a hexagon");
continue;
}


break;
}

}


puts(
"are not the vertices of an acceptable figure");

}


return 0;
}




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1595174


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值