南阳OJ 题目33:蛇形填数

本文详细解析了一种经典分治法应用——蛇形填数算法。通过将n*n方阵按层划分,并顺时针填充数字,最终形成蛇形排列。文章提供了完整的Java实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目信息:题目链接

蛇形填数

时间限制: 3000 ms  |  内存限制: 65535 KB
难度: 3
描述
在n*n方陈里填入1,2,...,n*n,要求填成蛇形。例如n=4时方陈为:
10 11 12 1
9 16 13 2
8 15 14 3
7 6 5 4
输入
直接输入方陈的维数,即n的值。(n<=100)
输出
输出结果是蛇形方陈。
样例输入
3
样例输出
7 8 1
6 9 2
5 4 3

思路分析:

           这是一道很经典的分治法题目,类似的题目像数字旋转方阵,都是这样的一个处理过程。
      首先,介绍一下,什么叫做分治法.
      分治法是一种解题策略,将问题划分成较小规模的子问题,再求解子问题,得到的子问题合并起来(具体问题具体的合并策略),合并的界即为原问题的解。
      划分子问题要将子问题划分为不可在分的原子问题(照样由题目的信息划分);
      求解子问题,这要根据具体的问题具体去求解,像排序问题是比较大小,最近对问题是求两点之间的距离。同样这样的求解子问题,不是只要求每一个原子问题就可以的了,在第一次划分的时候就要考虑到问题的解,可能出现在那些情况:划分的左边还是右边,或者是中间,像这样的,比较具有代表的就是最大字段和问题。
      最后一步是合并子问题
      上面是一些粗略的介绍,关于分治法建议多做几道经典的题型,像归并排序,快速排序,最大字段和问题,数字旋转方阵,最近对问题等,掌握其方法更为重要!

                             
                                                      
      分治法的解题步骤介绍了,接下来要讲解在这道题目中是如何运用的。
       i表示行,j表示列。
      首先第一步就是划分,如何划分呢?观察这个方阵发现,每一层中(这一个循环)数字是从右上角开始旋转,转了四下:从上到下(i++,j不变),从右到左(i不变,j--),从下到上(i--,j不变),从左到右(i不变,j++)。而在里面的每一层中,也是一样的规律。因此,我们以层作为代表来处理整个方阵。由刚才的旋转规分析,可以将层划分为四个并列的部分(并列的意思是处理完A之后,再处理B...而不是B在A中处理,这个说的好复杂的样子,看代码你就懂了~)

     划分为四个部分之后,求解每一部分,从右上角开始,顺时针旋转,当走到起点的时候,一层结束,然后进入到下一层:i行加一,j列减一开始,继续这样的一个数字旋转,其中你的方阵规模不再是第一次的那个n了(这个方阵规模指的是你当前数字旋转的那一层),减小为n-2。例:图中最外层的规模为4.接下来的那一层是2(4-2)。

      好了,现在你知道你的数字是如何划分的了,以及他的规律。现在最重要的是,也是分治法最关键的一部分,你程序的出口(大多数分治法采用的是递归的方法),这个题目,我们观察可以发现,当数字开始的下标i==j(n为奇数)或者i<j(n为偶数 )的时候,程序退出。
      ok,思维上的讲解就到这里,接下来看看代码是如何实现的。(我觉得我讲得乱七八糟的,还是看代码来得直接,更容易懂。)

代码实现:

package com.BasicThree;

import java.util.Scanner;  

/** 
     * Dragon 
     * 2017/4/28 
     */  
public class Num_33   
{  
  
    static int[][] snake=new int[101][101];  
    public static void main(String[] args)   
    {  
        Scanner in=new Scanner(System.in);  
        int n=in.nextInt();  
          
        GetSnake(n,1,n,1);  
        PrintSnake(n);
    }  
    
    private static void PrintSnake(int n)
    {
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				System.out.print(snake[i][j]+" ");
			}
			System.out.println();
		}
		
	}

    //方阵的下标是从1开始的!
	private static void GetSnake(int n, int startRow, int startCow, int number)  
    {  
		//程序出口
		if(startCow<startRow)
			return;
		
		if(startCow==startRow)
		{
			snake[startRow][startCow]=number;
			return;
		}
		
        int i=startRow;  
        for(int k=1;k<n;i++,k++)  
        {  
            snake[i][startCow]=number;  
            number++;  
        }  
          
        int j=startCow;  
        for(int k=1;k<n;j--,k++)  
        {  
            snake[i][j]=number;  
            number++;  
        }  
          
        for(int k=1;k<n;k++,i--)  
        {  
            snake[i][j]=number;  
            number++;  
        }  
          
        for(int k=1;k<n;k++,j++)  
        {  
            snake[i][j]=number;  
            number++;  
        }  
        
        GetSnake(n-2, startRow+1, startCow-1, number);
          
          
    }  
  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值