题目来源: mostleg
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注
如果一个由正整数组成的n*n的方阵,满足以下条件:

1,每个数字各不相同
2,每行以及每列的和,都是互不相同的完全平方数

我们称这种方阵为超级完全平方数方阵。
输入n,输出一个n*n的超级完全平方数方阵。如果存在多个方阵满足条件,输出将所有元素按行、列顺序排列后字典序最小的一个答案。例如
n=3时,下面两个方阵都符合条件

 1   2   6
 3   4   9
21 30 49

21 30 49
 3   4   9
 1   2   6

按行、列顺序排列后,第一个方阵表示为[1, 2, 6, 3, 4, 9, 21, 30, 49],第二个方阵表示为[21, 30, 49, 3, 4, 9, 1, 2, 6]。第一个方阵字典序更小一些。

如果不存在这样的方阵,输出No Solution。

Input
仅一行,为一个正整数n。(1 <= n <= 64)
Output
输出n行,每行为n个整数,之间用空格隔开,表示所求的n*n方阵。或者,输出No Solution。
Input示例
3
Output示例
1 2 6
3 4 9
21 30 49

真真正正地被虐了一下午。。。其实本质上就是一个dfs,但是做起来是真的麻烦啊,各种错误百出的。

官方题解:

首先,n=1时无解。


接下来处理n>=2的情况。由于题目要求字典序最小的方阵,使用贪心算法的思想,不难发现,每一行每一列其实只需要依靠最后一个数字(最右边和最下边的数字)就足够使得该行该列的和达到一个没有使用过的完全平方数。因此,按照题目中对方阵序列化的次序,对无关紧要的位置都尽力使用最小的数字;每当到达一行的最后一个位置,或者最后一行的时候,再去寻找符合题目要求的最后一个数字。这样做直到右下角的最后一个位置。

此时,最后一行和最后一列都需要满足和为完全平方数的条件。搜索最小的符合条件的数字。如果找不到解,就加大倒数第二个位置的数字(因为这样做对字典序的影响最小),再重新搜索最后一个位置。

怎样快速发现最后一个位置找不到解呢?不难发现,最后一列的和必定小于最后一行的和,设它们的差为d。我们可以枚举较小的一个完全平方数x,如果发现x的下一个完全平方数与x的差已经大于d,则在最后一个位置无解。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#include <map>
#pragma warning(disable:4996)
using namespace std; int n,wang=0;
int square_flag[10000];
int val_flag[64005];
long long val[70][70]; int sear(int su)
{
long long i;
for (i = 2; ; i++)
{
if (i*i >= su && ((i<=9999&&square_flag[i]==0)||(i>9999)))
return i;
}
} void dfs(int x,int y,long long value)
{
if (wang==1)
{
return;
}
if (x == n&&y == n)
{
long long i, j, h, k, sum2 = 0, sum3 = 0;
for (i = 1; i <= n - 1; i++)
{
sum2 += val[i][y];
}
for (i = 1; i <= n - 1; i++)
{
sum3 += val[x][i];
}
for (i = 2;; i++)
{
if ((i <= 9999 && square_flag[i] == 1))continue;
double g = sqrt((double)(i*i - sum2 + sum3)); if (i*i - sum2 > 0 && g == (long long)g && ((g<=9999)&&(square_flag[(long long)g] == 0)||g>9999))
{
val[x][y] = i*i - sum2;
for (h = 1; h <= n; h++)
{
for (k = 1; k <= n; k++)
{
cout << val[h][k]<< " ";
}
cout << endl;
}
wang = 1;
return;
}
long long wa = sum3 - sum2;
if ((i + 1)*(i + 1) - (i*i) > wa)
{
long long op, sum_op = 0;
for (op = 1; op <= n; op++)
{
sum_op += val[op][y - 1];
}
square_flag[(long long)sqrt((double)sum_op)] = 0;
dfs(x,y-1,value+1);
return;
}
}
}
else if (x == n)
{
long long i, sum2 = 0;
for (i = 1; i <= n - 1; i++)
{
sum2 += val[i][y];
}
i = sear(sum2 + value);
while (val_flag[i*i - sum2] == 1||square_flag[i]==1)
{
i++;
}
val[x][y] = i*i - sum2;
val_flag[i*i - sum2] = 1;
square_flag[i] = 1; dfs(x, y+1, value);
}
else if (y == n)
{
long long i,sum2=0;
for (i = 1; i <= n - 1; i++)
{
sum2 += val[x][i];
}
i = sear(sum2 + value); while (val_flag[i*i - sum2] == 1)
{
i++;
}
val[x][y] = i*i - sum2;
val_flag[i*i - sum2] = 1;
square_flag[i] = 1; dfs(x + 1, 1, value);
}
else
{
val[x][y] = value;
val_flag[value] = 1;
if (val_flag[value+1] == 0)
{
dfs(x, y + 1, value+1);
}
else
{
while (val_flag[value+1] == 1)
{
value++;
}
dfs(x, y + 1, value+1);
}
}
} int main()
{
scanf("%d", &n);
if (n == 1)
{
cout << "No Solution" << endl;
}
else
{
memset(square_flag,0,sizeof(square_flag));
memset(val_flag, 0, sizeof(val_flag)); dfs(1, 1, 1);
}
return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

51nod 1438:方阵与完全平方数的更多相关文章

  1. 51Nod 欢乐手速场1 C 开心的小Q[莫比乌斯函数]

    开心的小Q tangjz (命题人) quailty (测试)   基准时间限制:1 秒 空间限制:131072 KB 分值: 80 如果一个数字存在一个约数是完全平方数,那么小Q就认为这个数是有趣的 ...

  2. 51nod1787最大子方阵

    51nod1787最大子方阵 我在51nod上面切的第一道题 我在51nod上面切的第一道8级题 我在51nod上面切的第一道8级题的一血 题目大意 有一个n*m的矩阵,矩阵中的每一个元素是'X'或者 ...

  3. BZOJ 2440: [中山市选2011]完全平方数 [容斥原理 莫比乌斯函数]

    2440: [中山市选2011]完全平方数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3028  Solved: 1460[Submit][Sta ...

  4. 【51Nod 1244】莫比乌斯函数之和

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244 模板题... 杜教筛和基于质因子分解的筛法都写了一下模板. 杜教筛 ...

  5. [LeetCode] Valid Perfect Square 检验完全平方数

    Given a positive integer num, write a function which returns True if num is a perfect square else Fa ...

  6. [LeetCode] Perfect Squares 完全平方数

    Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 1 ...

  7. 51Nod 1268 和为K的组合

    51Nod  1268  和为K的组合 1268 和为K的组合 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 给出N个正整数组成的数组A,求能否从中选出若干个,使 ...

  8. 51Nod 1428 活动安排问题

    51Nod   1428  活动安排问题 Link: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1428 1428 活 ...

  9. 51Nod 1278 相离的圆

    51Nod 1278 相离的圆 Link: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1278 1278 相离的圆 基 ...

随机推荐

  1. 2-10 就业课(2.0)-oozie:5、通过oozie执行hive的任务

    4.2.使用oozie调度我们的hive 第一步:拷贝hive的案例模板 cd /export/servers/oozie-4.1.0-cdh5.14.0 cp -ra examples/apps/h ...

  2. docker中使用mongodb

    连接mongodb容器,下拉alpine应用测试连接

  3. springboot启动不能加载数据库驱动Failed to determine a suitable driver class

    SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/G:/sharp/repo ...

  4. android侧滑效果(引用官方网站提供的API文件)

    原文地址:http://www.cnblogs.com/android100/p/android-SlidingMenu.html 在新浪微博和唱吧里面都有看到android的侧滑效果,于是想要学习一 ...

  5. Xilinx Vivado器件分配管脚:LVDS差分电平信号如何分配管脚?

    最近在把Quartus Prime 15.1的工程移植到Vivado 2019.1,需要改变的地方还是很多的,先记一下差分信号在FPGA中的收发管脚定义和配置.以LVDS信号为例吧. 在7 Serie ...

  6. editplus的注册码 4.0

    用户名:jb51.net 序列号:9A72F-84A30-82Z46-BFW79-4FTA8 用户名:freeuser 序列号:F15AD-12490-DAZF5-E4W30-E7T80 注册名:Fr ...

  7. Charles抓包(HTTP)

    一.电脑抓包: 安装Charles,打开Charles即可 二.手机抓包: 设置手机WiFi配置代理即可:(确保电脑和手机在同一个网络) 三.拦截请求: 四.修改请求/返回: 打上断点后,刷新页面,在 ...

  8. Linux添加虚拟内存 && 修改Linux系统语言

    Linux添加虚拟内存 首先执行free -h查看内存状况: total used free shared buff/cache available Mem: 1.8G 570M 76M 8.4M 1 ...

  9. POJ 3061:Subsequence 查找连续的几个数,使得这几个数的和大于给定的S

    Subsequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10172   Accepted: 4160 Desc ...

  10. 024-PHP常用字符串函数(一)

    <?php $first = "abc"; $second = "aBc"; )//字串比较 { print("字符串相等:".&qu ...