2013
12-16

# Forests

The saying “You can’t see the wood for the trees” is not only a cliche, but is also incorrect. The real problem is that you can’t see the trees for the wood. If you stand in the middle of a “wood” (in NZ terms, a patch of bush), the trees tend to obscure each other and the number of distinct trees you can actually see is quite small. This is especially true if the trees are planted in rows and columns (as in a pine plantation), because they tend to line up. The purpose of this problem is to find how many distinct trees you can see from an arbitrary point in a pine plantation (assumed to stretch “for ever”).

You can only see a distinct tree if no part of its trunk is obscured by a nearer tree–that is if both sides of the trunk can be seen, with a discernible gap between them and the trunks of all trees closer to you. Also, you can’t see a tree if it is apparently “too small”. For definiteness, “not too small” and “discernible gap” will mean that the angle subtended at your eye is greater than 0.01 degrees (you are assumed to use one eye for observing). Thus the two trees markedobscure at least the trees markedfrom the given view point.Write a program that will determine the number of trees visible under these assumptions, given the diameter of the trees, and the coordinates of a viewing position. Because the grid is infinite, the origin is unimportant, and the coordinates will be numbers between 0 and 1.

Input will consist of a series of lines, each line containing three real numbers of the form 0.nn. The first number will be the trunk diameter–all trees will be assumed to be cylinders of exactly this diameter, with their centres placed exactly on the points of a rectangular grid with a spacing of one unit. The next two numbers will be the x and y coordinates of the observer. To avoid potential problems, say by being too close to a tree, we will guarantee that To avoid problems with trees being too small you may assume that. The file will be terminated by a line consisting of three zeroes.

Output will consist of a series of lines, one for each line of the input. Each line will consist of the number of trees of the given size, visible from the given position.

0.10 0.46 0.38
0 0 0

128

## 分析

#include <iostream>
#include <cmath>
using namespace std;
//用于存储坐标的结构体
struct POINT{int x; int y;};
//主函数
int main(void) {
//dMax为cos(0.01)，任何大于此值的参数都不能进行acos
const float fMax = 0.99999998476912904932780850903444f;
//循环处理每一组输入的数据，d为直径，x和y为观查者坐标
for (float d, x, y; cin >> d >> x >> y && d != 0; ) {
//将所有值放大100倍并取整，一可加快运算，二可保证精度
POINT Eye = {int(x * 100 + 0.5), int(y * 100 + 0.5)};
int nDiam = (int)(d * 100 + 0.5), nCnt = 0;
//依次由里圈向外层层遍例每棵树，检查是否被里面的树遮挡
for (int iBeg = 0, iEnd = 100; iEnd <= 1000;
iBeg -= 100, iEnd += 100) {
//遍例外面这一圈的树
for (int i = 0; i < iEnd - iBeg; i += 100) {
POINT Out[4] = {//一圈分别为左边、上边
{iBeg, iBeg + i}, {iBeg + i, iEnd},
//右边和下边
{iEnd, iEnd - i}, {iEnd - i, iBeg}};
//遍例四条边上的树
for (int j = 0; j < 4; j++) {
//遍例圈里面所有的树，In为树的坐标
POINT In = {iBeg + 100, iBeg + 100};
for (; In.y <= iEnd - 100; In.y += 100) {
for (In.x = iBeg + 100; In.x <= iEnd - 100;
In.x += 100) {//以下算法判定两棵树是否遮挡
//分别建立里面树和处面树与眼睛坐标的向量
POINT NVec = {In.x - Eye.x, In.y - Eye.y};
POINT FVec = {Out[j].x - Eye.x, Out[j].y - Eye.y};
//两个向量求内积
int nProd = NVec.x * FVec.x + NVec.y * FVec.y;
//求两个向量的模
float fNMod = sqrt((float)(NVec.x * NVec.x +
NVec.y * NVec.y));
float fFMod = sqrt((float)(FVec.x * FVec.x +
FVec.y * FVec.y));
//内积公式求夹角
float fACOS = nProd / (fNMod * fFMod);
if (fACOS >= fMax) { //夹角不能大于cos(0.01)
break;
}
//求出夹角角度
float fAng = acos(fACOS) * fRad;
//分别计算两棵树干自身与眼睛形成的的夹角
fNMod = asin((float)nDiam / 2.0f / fNMod) * fRad;
fFMod = asin((float)nDiam / 2.0f / fFMod) * fRad;
//判断是否遮挡，如果有则跳出循环
if (fAng - fNMod - fFMod <= 0.01f) {
break;
}
}
//未完成内循环，说明存在遮挡，继续向外跳出
if (In.x <= iEnd - 100) {
break;
}
}
//累计可见树的个数
nCnt += (In.y > iEnd - 100);
}
}
}
//输出结果
cout << nCnt << endl;
}
return 0;
}

1. 其实国内大部分公司对算法都不够重视。特别是中小型公司老板根本都不懂技术，也不懂什么是算法，从而也不要求程序员懂什么算法，做程序从来不考虑性能问题，只要页面能显示出来就是好程序，这是国内的现状，很无奈。