本帖最后由 _J2EE_LiXiZhen 于 2017-11-5 22:37 编辑
题目大意:给出一个nxm的矩阵,现在从某点开始遍历所有点并回到起始点,问最少的遍历路程是多少?(从某点出发有8个方向,行上相邻的点之间的距离是1。)
数理分析:其实这道题目的描述非常有误导性,多次强调所谓“旅行销售员问题”,也就是当现在还没有得到很好解决的著名的TSP问题,这就很容易将人带向很混乱的思维。但是这道题目基于比较特殊的矩阵图,我们应该能够更加简单的方法。
我们首先应该考虑到的一个贪心策略,行走距离为1的利益最大化就是访问到了一个节点(当然不算起始节点),那么如果有这样一种方案使得我们,遍历距离+1,都会导致多访问了1个节点,那么这最终一定会导致最小的路程,即节点个数mn。
那么下面我们所关注的问题便是,是否存在这样一个策略呢?如果m列是偶数,那么连接相邻节点形成小正方格,就会形成奇数列个小方格,这使得我们能够有一个走“S”型的锯齿状的遍历策略,能够使我们完成贪心策略。
即我们能够得到结论,如果m、n当中有一个是偶数,最小距离都是mn。
那么如果m、n都是奇数呢?依然从m列入手,我们基于(m-1)xn这样一个矩阵,那么我们可以采取和上面类似的思路进行贪心化的遍历,由此我们其实能够看到,对于这种情况,是没有一种路程为mn的便利方案的,但对于剩下的两列,一开始我们令遍历路线走一个长为1.41的“斜边”,然后由原来的纵向S型变成横向S型,即路程为mn + 0.41,这是除去路程为mn的最优方案。
上文给出的文字描述可能过于抽象,读者可以自行画图感受一下。
综合起来我们能够得到这道问题线性算法:
m、n存在一个偶数,结果是mn。
否自,结果是mn + 0.41.
![]()
简单的参考代码如下:
[C] 纯文本查看 复制代码
#include<cstdio>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
int tt =1;
while(t--)
{
int n , m;
scanf("%d %d",&n,&m);
if(n % 2 == 0 || m%2 == 0)
printf("Scenario #%d:\n%d.00\n",tt++,m*n);
else
printf("Scenario #%d:\n%d.41\n",tt++,m*n);
printf("\n");
}
} |