问题:android手机的锁屏屏幕,手指划过的距离最长为多少?
解法:
1、 这个题目首先可以判断要出现最长的滑动距离,必然是9个点都是用。
2、 约束条件:连接两个点之间的途径的那个点必须已经连接,这两个点才能连接。
3、 解决思想:
解决方法是通过递归方式遍历所有的9个点的连接方式,并计算每种连接方式的总长度,通过比较得到最长的长度值。
其中规定规定同一行两个相邻的点之间的距离为1。代码实现如下(有详细注释解释):
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<conio.h>
//规定同一行两个相邻的点之间的距离为1。
const float LENGTH_A = 1.0f;
const float LENGTH_B = 2.0f;
const float LENGTH_C = 1.4f;
const float LENGTH_D = 2.8f;
const float LENGTH_E = 2.2f;
//用于存放选出的点
int squared[3][3] = {0};
//int count = 0;
int nCount = 0;
float maxLength = 0.0;
int xPrePos = -1;
int yPrePos = -1;
//判断此点是否已被占
int IsOccupied(int x, int y)
{
if (squared[x][y])
return 1;
else
return 0;
}
//判断两个点横向之间间隔的点是否已被占
int CheckIfMidllePosOfHorizontalIsOccupied(int x)
{
if (0 == IsOccupied(x, 1))
return 0;
else
return 1;
}
//判断两个点纵向之间间隔的点是否已被占
int CheckIfMidllePosOfVerticalIsOccupied(int y)
{
if (0 == IsOccupied(1, y))
return 0;
else
return 1;
}
//判断对角线中间的点是否被占
int CheckIfMidllePosOfDiagonalIsOccupied()
{
if (0 == IsOccupied(1, 1))
return 0;
else
return 1;
}
//判断一个点是否是四个顶点中的一个
int CheckIfPosIsCorner(int x, int y)
{
if ((0 == (x + y)) || (4 == (x + y)) || ((x != y) && (2 == (x + y))))
return 1;
else
return 0;
}
//查找前一个点的位置
void GetPrePos(int n)
{
int x, y;
for(x = 0; x < 3; x++)
{
for(y = 0;y < 3; y++)
{
if(squared[x][y] == n-1)
{
xPrePos = x;
yPrePos = y;
return;
}
}
}
}
//判断当前位置是否可以被占
int CheckIfPosCanBeOccupied(int x, int y, int n)
{
//如果这个位置没有被占用,进行放置的判断
if (0 == IsOccupied(x, y))
{
//如果是第一个节点则直接放置,不用下面判断
if (1 == n)
return 1;
//结合这个节点之前已经放置的节点判断当前节点是否可以被连接占用
//通过判断这两个节点横坐标是否相同确定这两个点是否在同一行,进而判断
//这两点的纵坐标差的绝对值是否等于2来确定这两个点横向之间是否存在中间点
//当存在中间间隔点时,再调用CheckIfMidllePosOfHorizontalIsOccupied()
//判断中间点是否被占。
else
{
xPrePos = -1;
yPrePos = -1;
GetPrePos(n);
if (x == xPrePos && (2 == abs(y - yPrePos)))
{
if (CheckIfMidllePosOfHorizontalIsOccupied(x))
//中间节点已被占,此节点可占
return 1;
else
//中间节点未被占,此节点不可占
return 0;
}
//结合这个节点之前已经放置的节点判断当前节点是否可以被连接占用
//通过判断这两个节点是否是四个顶点中的两个,进而判断
//这两点是否正好处于对角线的两端来确定这两个点纵向之间是否存在中间点
//当存在中间间隔点时,再调用CheckIfMidllePosOfVerticalIsOccupied()
//判断中间点是否被占。
else if (y == yPrePos && (2 == abs(x - xPrePos)))
{
if (CheckIfMidllePosOfVerticalIsOccupied(y))
//中间节点已被占,此节点可占
return 1;
else
//中间节点未被占,此节点不可占
return 0;
}
//结合这个节点之前已经放置的节点判断当前节点是否可以被连接占用
//通过判断这两个节点纵坐标是否相同确定这两个点是否在同一列,进而判断
//这两点的横坐标差的绝对值是否等于2来确定这两个点纵向之间是否存在中间点
//当存在中间间隔点时,再调用CheckIfMidllePosOfDiagonalIsOccupied()
//判断中间点是否被占。
else if (CheckIfPosIsCorner(x, y) && CheckIfPosIsCorner(xPrePos, yPrePos) && ((x != xPrePos) && (y != yPrePos)))
{
if (CheckIfMidllePosOfDiagonalIsOccupied())
return 1;
else
return 0;
}
else
return 1;
}
}
else
return 0;
}
//计算两点之间的长度
float LengthOfTwoNodes(int x, int y, int xPre, int yPre)
{
if ((abs(x - xPre) + abs(y - yPre)) == 1)
return LENGTH_A;
else if ((abs(x - xPre) + abs(y - yPre)) == 4)
return LENGTH_D;
else if ((abs(x - xPre) + abs(y - yPre)) == 3)
return LENGTH_E;
else if (((abs(x - xPre) + abs(y - yPre)) == 2) && (x != xPre && y != yPre))
return LENGTH_C;
else
return LENGTH_B;
}
//计算当前连接方式的总长度
float CalculateLength()
{
int x, y, xPre = -1, yPre = -1;
float length = 0;
for (int k = 1; k < 10; k++)
{
for(x = 0; x < 3; x++)
{
for(y = 0; y < 3; y++)
{
if(squared[x][y] == k)
{
//printf("qw = %d",squared[x][y]);
//getchar();
if (k > 1)
length+= LengthOfTwoNodes(x, y, xPre, yPre);
//printf("length == %f",length);
xPre = x;
yPre = y;
}
}
}
}
return length;
}
//递归遍历所有连接方式并计算总长度,得到最大长度。
void LongestPathOfAndroidScreenLock(int n)
{
int x, y;
if (n == 10)
{
//CalculateLength();
if (CalculateLength() > maxLength)
maxLength = CalculateLength();
//printf("len = %f",maxLength);
//nCount++;
return;
}
for (x = 0; x < 3; x++)
{
for (y = 0; y < 3; y++)
{
if (CheckIfPosCanBeOccupied(x, y, n))
{
//xPrePos = x;
//yPrePos = y;
squared[x][y] = n;
//count++;
LongestPathOfAndroidScreenLock(n + 1);
squared[x][y] = 0;
}
}
}
}
int main()
{
LongestPathOfAndroidScreenLock(1);
printf("\nThe longest distance for Android screen lock is : %f\n",maxLength);
system("pause");
return 0;
}