当前位置: 首页 > article >正文

OpenJudge NOI 1.8 24:蛇形填充数组

【题目链接】

OpenJudge NOI 1.8 24:蛇形填充数组

【题目考点】

1. 二维数组

【解题思路】

解法1:移动焦点

设焦点位置,焦点移动同时为焦点位置赋值。焦点移动规则为:

  • 移动到右上角时,行加1
  • 移动到左下角时,列加1
  • 移动到第一行或第n行时,列加1
  • 移动到第一列或第n列时,行加1

不断移动焦点,填充整个矩阵,最后输出矩阵。

解法2:遍历矩阵

下标从1开始,每条右上左下斜线上的位置的行列坐标加和是一定的,第一条斜线的加和为2,第二条为3,。。。,最后一条即第2n-1条斜线加和为2n。每次遍历整个矩阵,为一条斜线赋值。
观察规律可知:

  • 斜线编号为奇数的斜线,数字是从左下向右上填充的,行减少列增加。
  • 斜线编号为偶数的斜线,数字是从右上向左下填充的,行增加列减少。

每次填充一条斜线,填充整个矩阵,最后输出矩阵。

解法3:数学计算

斜线值:每条右上左下斜线上的位置的行号与列号的加和是相同的,记该加和为斜线值。例:(i, j)所在斜线的斜线值为i+j。
该解法可以通过位置的行号i、列号j直接求出(i, j)位置的值。

1. 对于左上方三角矩阵(包括副对角线)中的某位置(i, j)

该矩阵为n*n的矩阵,因此副对角线(右上左下)的斜线值为n+1。
因此左上方三角矩阵(包括副对角线)中的所有斜线值满足: i + j ≤ n + 1 i+j\le n+1 i+jn+1
在这里插入图片描述

对于左上方三角矩阵(包括副对角线)中的某位置(i, j),其所在斜线的值 k = i + j k=i+j k=i+j
考虑该斜线左上方(不包括该斜线)的位置数:
第1条斜线,斜线值为2,有1个元素,
第2条斜线,斜线值为3,有2个元素,
。。。
第k-2条斜线,斜线值k-1,有k-2个元素。
共有元素: 1 + 2 + . . . + k − 2 = ( k − 1 ) ∗ ( k − 2 ) / 2 1+2+...+k-2 = (k-1)*(k-2)/2 1+2+...+k2=(k1)(k2)/2
因此从(1,1)以蛇形方式走到斜线值为k的斜线前,共经过元素 ( k − 1 ) ∗ ( k − 2 ) / 2 (k-1)*(k-2)/2 (k1)(k2)/2个位置,已经填充了数字 1 1 1 ( k − 1 ) ∗ ( k − 2 ) / 2 (k-1)*(k-2)/2 (k1)(k2)/2
再考虑到达斜线值为k的斜线上后走到(i,j)所经过的元素个数

  • 如果k是偶数,则为从左下向右上走,从(i+j-1,1)走到(i,j)时走过的数字为j个
  • 如果k是奇数,则为从右上向左下走,从(1,i+j-1)走到(i,j)时走过的数字为i个

因此(i,j)位置的值为(k-1)*(k-2)/2+(k%2==0?j:i)

2. 对于右下方三角矩阵(不包括副对角线)中的某位置(i, j)

对于右下方三角矩阵(不包括副对角线)中的某位置(i, j),其所在斜线的值 k = i + j k=i+j k=i+j
考虑该斜线左上方(不包括该斜线)的位置数:
第1条斜线,斜线值为2,有1个元素,
第2条斜线,斜线值为3,有2个元素,
。。。
第n条斜线,斜线值为n+1,有n个元素
第n+1条斜线,斜线值为n+2,有n-1个元素
第n+2条斜线,斜线值为n+3,有n-2个元素
。。。(规律:斜线值和该线上元素个数加和为2*n+1)
第k-2条斜线,斜线值k-1,有 ( 2 ∗ n + 1 − ( k − 1 ) ) = 2 ∗ n + 2 − k (2*n+1-(k-1))=2*n+2-k (2n+1(k1))=2n+2k个元素。
前n条斜线的元素数量: ( 1 + n ) n / 2 (1+n)n/2 (1+n)n/2
第n+1条斜线到第k-2条斜线的元素数量: ( n − 1 + 2 ∗ n + 2 − k ) ∗ ( k − 2 − ( n + 1 ) + 1 ) / 2 = ( 3 ∗ n + 1 − k ) ∗ ( k − n − 2 ) / 2 (n-1+2*n+2-k)*(k-2-(n+1)+1)/2=(3*n+1-k)*(k-n-2)/2 (n1+2n+2k)(k2(n+1)+1)/2=(3n+1k)(kn2)/2
再考虑到达斜线值为k的斜线上后走到(i,j)所经过的元素个数

  • 如果k是偶数,则为从左下向右上走,从(n,i+j-n)走到(i,j)时走过的数字为n-i+1个
  • 如果k是奇数,则为从右上向左下走,从(i+j-n,n)走到(i,j)时走过的数字为n-j+1个
    因此(i,j)位置的值为(1+n)n/2+(3*n-k+1)*(k-n-2)/2+(k%2==0?n-i+1:n-j+1)

另一种求右下方三角矩阵(不包括副对角线)中的某位置(i, j)的值的方法:可以取矩阵中与(i,j)中心对称的位置(n-i+1, n-j+1),这两个位置的加和一定为n*n+1。
因此a[i][j] = n*n+1-a[n-i+1][n-j+1]

【题解代码】

解法1:移动焦点
#include<bits/stdc++.h>
using namespace std;
int a[15][15], dir[2][2]={{-1,1},{1,-1}};//两种方向:右上、左下 
int main()
{int k = 1, n, i, j, d = 0, si, sj;//(si,sj):拟定的下一个位置 cin >> n;i = j = 1;//(i,j):当前位置 while(k <= n*n){a[i][j] = k++;si = i + dir[d][0], sj = j + dir[d][1];if(si >= 1 && si <= n && sj >= 1 && sj <= n)//如果下一个位置在边界内 i += dir[d][0],  j += dir[d][1];else//下一个位置在边界外 {d = (d+1)%2;//改变移动方向if(i == 1 && j != n || i == n)//如果在第一行或最后一行(不包括右上角),到下一列 j++;else if(j == 1 && i != n || j == n)//如果在第一列或最后一列(不包括左下角),到下一行 i++;}}for(int i = 1; i <= n; ++i){for(int j = 1; j <= n; ++j)cout << a[i][j] << ' ';cout << endl;}return 0; 
}
解法2:遍历矩阵
#include <bits/stdc++.h>
using namespace std;
int a[15][15];
int main(){int n, k = 1;cin >> n;for(int m = 1; m <= 2*n-1; m++)//m为斜线编号,即每条斜线的行列坐标加和减1 {if(m%2 == 0)//斜线编号为偶数的斜线,数字是从右上向左下填充的,行增加列减少。{for(int i = 1; i <= n; i++)for(int j = n; j >= 1; j--)if(i + j == m + 1)//第m条斜线的行列坐标加和为m+1 a[i][j] = k++;}else//斜线编号为奇数的斜线,数字是从左下向右上填充的,行减少列增加。{for(int i = n; i >= 1; --i)for(int j = 1; j <= n; ++j)if(i + j == m + 1)a[i][j] = k++;    }}for(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++)cout << a[i][j] << ' ';cout << endl;}return 0;
}
解法3:数学计算
  • 方法1:规律推导
#include<bits/stdc++.h>
using namespace std;
#define N 105
int main()
{int n, k, a[N][N];cin >> n;for(int i = 1; i <= n; ++i)for(int j = 1; j <= n; ++j){k = i+j;//斜线编号 if(k <= n+1)a[i][j] = (k-1)*(k-2)/2+(k%2==0?j:i);elsea[i][j] = (1+n)*n/2+(3*n-k+1)*(k-n-2)/2+(k%2==0?n-i+1:n-j+1);}for(int i = 1; i <= n; ++i){for(int j = 1; j <= n; ++j)cout << a[i][j] << ' ';cout << endl;}return 0;
}
  • 方法2:利用中心对称
#include<bits/stdc++.h>
using namespace std;
#define N 105
int getVal(int i, int j)//获取左上方三角形矩阵中(i,j)位置的值 
{return (i+j-1)*(i+j-2)/2+((i+j)%2 == 0 ? j : i);
}
int main()
{int a[N][N], n, k;cin >> n;for(int i = 1; i <= n; ++i)for(int j = 1; j <= n; ++j){k = i+j;//斜线编号 if(k <= n+1)a[i][j] = getVal(i, j);elsea[i][j] = n*n+1-getVal(n-i+1, n-j+1);}for(int i = 1; i <= n; ++i){for(int j = 1; j <= n; ++j)cout << a[i][j] << ' ';cout << endl;}return 0;
}
http://www.lryc.cn/news/2420260.html

相关文章:

  • 凯撒密码加密和解密的算法实现
  • MYSQL中什么是规范化_数据库规范化原理基础介绍
  • Zookeeper安装部署与基本使用
  • 数据结构—平衡二叉树(AVL树)的原理以及Java代码的完全实现
  • 通达OA工作流设计-关联子菜单(多级联动)及数据选择控件应用
  • static_cast、const_cast用法
  • 802.11 a/b/g/n/ac/ax/be 有什么区别
  • HTTP状态码——413
  • API网关的6个主要作用(非常详细)零基础入门到精通,收藏这一篇就够了
  • A级IDC数据机房具体是怎么样的?
  • origin绘图软件中文版下载和安装教程
  • 什么是类?以及类的分类
  • 什么是非对称加密?非对称加密算法介绍
  • 集群联邦(Federation)
  • Wubi安装Ubuntu 12.04
  • 编译原理(二)词法分析:3.记号的识别―NFA与DFA
  • ospf和bgp协议知识详解
  • PHP substr()函数教程
  • STM32H563 LWIP裸机移植 (包含源代码 一文搞定 )
  • Ehcache和Redis封装接口(支持缓存切换)
  • 高性能并发队列Disruptor使用详解,详细解析Disruptor框架的应用和基本原理
  • C/C++中随机函数rand()和srand()的用法
  • static routing
  • 搭建论坛那些小事儿(phpwind、wordpress)
  • SVN(subversion)-简单介绍
  • java过滤字符串前后特殊空格字符 NBSP
  • WSDL、详解
  • 浅谈反编译在项目中的使用
  • 一篇文章搞懂,CCM、DCM、BCM
  • Python中datetime ,date ,time 各有什么区别和优缺点