森森最近想让自己的朋友圈熠熠生辉,所以他决定自己写个美化照片的软件……
看了这位兄弟的才看得懂是怎么回事,要学会大概怎么做看他的就够了。
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
很棒,写完了,晚安 ^-^>