曼哈顿距离
定义
出租车几何或曼哈顿距离(Manhattan Distance)是由十九世纪的赫尔曼·闵可夫斯基所创词汇 ,是种使用在几何度量空间的几何学用语,用以标明两个点在标准坐标系上的绝对轴距总和。
两点在南北方向上的距离加上在东西方向上的距离d(i,j)=|X1-X2|+|Y1-Y2|
数学性质
- 非负性:d(i,j)≥0 距离是一个非负的数值
- 同一性:d(i,i)= 0 对象到自身的距离为0
- 对称性:d(i,j)= d(j,i)距离是一个对称函数
- 三角不等式:
d(i,j)≤d(i,k)+d(k,j)
从对象i到对象j的直接距离不会大于途经的任何其余对象k的距离
曼哈顿距离解决什么问题呢?
曼哈顿距离可以代替一个广搜,不过这个广搜是有条件限制的:
①只能上、下、左、右四个方向进行移动(很多迷宫问题其实都有这个特性)
②只求两点之间最短路径的长度,不求路径过程 。
例如
Description
在一个 N 行 M 列的字符网格上, 恰好有 2 个彼此分开的连通块。每个连通 块的一个格点与它的上、下、左、右的格子连通。如下图所示:现在要把这 2 个连通块连通, 求最少需要把几个’.’转变成’X’。上图的例子中, 最少只需要把 3个’.’转变成’X’。下图用’*’表示转化为’X’的格点。
Input
第 1 行:2 个整数 N 和 M(1<=N,M<=50) 接下来 N 行,每行 M 个字符, ’X’表示属于某个连通块的格点,’.’表示不属于某 个连通块的格点
Output
第 1 行:1 个整数,表示最少需要把几个’.’转变成’X’
Sample Input
6 16
…
…XXXX…XXX…
…XXXX…XX…
.XXXX…XXX…
…XXXXX…
…XXX…
Sample Output
3
有两种解法,一种是先用 DFS 把两个联通块区分开来,然后用 BFS求最短距离。另一种就是笔者要讲的 DFS + 曼哈顿距离。
代码如下
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=50;
char g[N][N];
struct Node
{
int x,y;
}Edge;
vector<Node> dist[2];
int n,m,cnt;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
void dfs(int a,int b)
{
g[a][b] = '.'; //避免重复搜索
Edge.x = a;
Edge.y = b;
dist[cnt].push_back(Edge);
for(int i=0;i<4;i++)
{
int x = a + dx[i];
int y = b + dy[i];
if(x >= 0 && y >= 0 && x < n && y < m && g[x][y] == 'X')
dfs(x, y);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",g[i]);
cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(g[i][j] == 'X') //搜到一个连通块
{
dfs(i,j);
cnt ++;
}
int ans = 0x3f3f3f3f;
for(int i=0;i<dist[0].size();i++)
{
for(int j=0;j<dist[1].size();j++)
{
ans = min(ans, abs(dist[0][i].x - dist[1][j].x) + abs(dist[0][i].y - dist[1][j].y) - 1);
}
}
printf("%d\n",ans);
return 0;
}
再来一道娱乐题
菱形
输入一个奇数 n,输出一个由 * 构成的 n 阶实心菱形。
输入格式
一个奇数 n。
输出格式
输出一个由 * 构成的 n 阶实心菱形。
具体格式参照输出样例。
数据范围
1≤n≤99
输入样例:
5
输出样例:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
int sx = n / 2, sy = n / 2;
for (int i = 0; i < n ; i ++ )
{
for (int j = 0; j < n; j ++ )
{
if ( abs(sx - i) + abs(sy - j) <= n / 2 ) cout << "*";
else cout << " ";
}
cout << endl;
}
return 0;
}