L3-018 森森美图 (30 分)计算几何 + BFS

 森森最近想让自己的朋友圈熠熠生辉,所以他决定自己写个美化照片的软件……

 看了这位兄弟的才看得懂是怎么回事,要学会大概怎么做看他的就够了。

https://blog.csdn.net/Solitarily/article/details/79473754

 接下来的是我总结的一些小细节和知识点:

1.为什么要让初始点和结束点的坐标都加上1呢? 只是用来方便观察的吗? 见如下代码段:
 

next_k.x = now.x + dir1[i][0];
next_k.y = now.y + dir1[i][1];
next_k.dis = fdis[now.x][now.y] + score[next_k.x][next_k.y];

 

如果next_k的坐标在没有经过判定的前提下去取值(fdis score), 如果是从0开始存放的,那么会面临非法访问存储位置的风险。

2.memset对浮点数组赋值的时候不能使用0x3f3f3f3f,否则赋出来的值会是0.000476792279412。

https://www.luogu.org/discuss/show/46724

3.计算几何初探

int cross(point A, point B, point P)
{
    return (B.x - A.x) * (P.y - A.y) - (P.x - A.x) * (B.y - A.y);
}

这个是利用二维向量的叉乘来实现:

判断点在直线的哪一边——就本题而言

计算三角形的面积

据我观察和猜测,完全不懂背后的道理,没有经过计算和推导,应当是这样子的情况:(所以,仅供参考)

就上面那个公式和本题的样例来说:

上面的函数是在计算向量AP和向量AB的叉乘(叉乘的计算:(a1,b1) X (a2,b2) = a1b2-a2b1 )

如果P在直线AB(A是起始点,B是终止点)的上方,那么向量AB可以以不超过180°的角度逆时针旋转到AP——这时候叉乘的结果是大于0的,在应用右手定则的情况下,大拇指指尖朝向垂直向量所在水平面向上

如果P在直线AB(A是起始点,B是终止点)的下方,那么向量AB要以超过180°的角度逆时针旋转到AP——这时候叉乘的结果是小于0的,在应用右手定则的情况下,大拇指指尖朝向垂直向量所在水平面向下。

如果P在直线AB(A是起始点,B是终止点)上,A、B、P共线——这时候叉乘的结果是等于0的

 

其实你也可以写成  return (A.x - P.x) * (B.y - P.y) - (Y.x - P.x) * (A.y - P.y);(PA和向量PB的叉乘)

关键在于什么呢?

 (1)谁是旋转点

 (2)不定点(如题中的点P)在直线上方(下方)的时候,做逆时针旋转,从旋转起始边到旋转终止边经过的角度是多少——将会固定为大于180°或者小于180°,这决定了叉乘的正负号

   理一下思路:(以本题样例为例)

  如果我选择A作为旋转点,AB作为旋转起始边,AP作为旋转终止边,我会发现P在AB上方时,AB旋转角度小于180°,那么AB和AP的叉乘就大于0。

  (3)叉乘函数书写注意事项,写出两个向量后,一定是起始边的a1乘以终止边的b2,减去(终止边的a2乘以起始边的b1),否则计算结果的正负号就和你探索出来的正负号相反了

4.最终要求的轮廓曲线得分和 用fdis二维数组中的终止点所在位置的值分两次存放上方曲线得分和 与 下方曲线得分和,如果用一个int变量动态存放得分和会很难——在我看来。其实还是最短路中d数组的应用,之前我以为写出直捣黄龙就是dij的一个高峰了,但是显然思维的运用是并不死板的。

 

 

代码:

#include
using namespace std;
#define inf 0x3f3f3f3f
#define ull unsigned long long
#define maxn 105
typedef struct point {
	int x, y;
	double dis;
	bool operator != (const point& a)const
	{
		return a.x != x || a.y != y;
	}
} point ;
queue q;
point start, end_k, now, next_k;
int cross(point A, point B, point P)
{
	return (B.x - A.x) * (P.y - A.y) - (P.x - A.x) * (B.y - A.y);
}
double score[maxn][maxn];
int N, M;
int dir1[][2] = { { -1, 0}, {1, 0}, {0, -1}, {0, 1} };
int dir2[][2] = { { -1, -1}, {1, 1}, {1, -1}, { -1, 1} };
double fdis[maxn][maxn];
int where;
void test(point en)
{
	if (en.x < 1 || en.x > N || en.y < 1 || en.y > M) return ;
	if (en.dis >= fdis[en.x][en.y]) 		   return ;
	if ( where && en != start && en != end_k && cross(start, end_k, en) <= 0 ) return;
	if (!where && en != start && en != end_k && cross(start, end_k, en) >= 0 ) return;
	fdis[en.x][en.y] = en.dis;
	if (en != start && en != end_k) q.push(en);
}
void bfs()
{
	while (!q.empty()) q.pop();
	int i, j, k;
	q.push(start);
	while (!q.empty())
	{
		now = q.front();	q.pop();
		for (i = 0; i < 4; ++i)
		{
			next_k.x = now.x + dir1[i][0];
			next_k.y = now.y + dir1[i][1];
			next_k.dis = fdis[now.x][now.y] + score[next_k.x][next_k.y];
			test(next_k);
		}
		for (i = 0; i < 4; ++i)
		{
			next_k.x = now.x + dir2[i][0];
			next_k.y = now.y + dir2[i][1];
			next_k.dis = fdis[now.x][now.y] + score[next_k.x][next_k.y] + (sqrt(2) - 1) * ( score[now.x][now.y] + score[next_k.x][next_k.y]);
			test(next_k);
		}
	}
}

int main()
{
	cin >> N >> M;
	int i, j, k;
	for (i = 1; i <= N; ++i) for (j = 1; j <= M; ++j) scanf("%lf", &score[i][j]);
	cin >> start.y >> start.x >> end_k.y >> end_k.x;
	++start.y; ++start.x; ++end_k.y; ++end_k.x;
	start.dis  = score[start.x][start.y];
	double ans = 0;
	for (i = 1; i <= N; ++i) for (j = 1; j <= M; ++j) fdis[i][j] = inf;
	fdis[start.x][start.y] = score[start.x][start.y]; where = 1; bfs(); ans += fdis[end_k.x][end_k.y];
	for (i = 1; i <= N; ++i) for (j = 1; j <= M; ++j) fdis[i][j] = inf;
	fdis[start.x][start.y] = score[start.x][start.y]; where = 0; bfs(); ans += fdis[end_k.x][end_k.y];
	printf("%.2lf", ans - score[start.x][start.y] - score[end_k.x][end_k.y]);
	return 0;
}

__________________________________

2019-1-30 23:02:29

很棒,写完了,晚安 ^-^>

你可能感兴趣的:(GPLT)