zoukankan      html  css  js  c++  java
  • 51nod 1438:方阵与完全平方数

    题目来源: 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;
    }
    




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

  • 相关阅读:
    Centos下 安装和测试kafka
    Java枚举
    Java 数组
    Java变量
    Java标识符
    Java修饰符
    java 基本语法
    Java 基础语法
    Java开发工具
    JAVA 发展历史
  • 原文地址:https://www.cnblogs.com/lightspeedsmallson/p/4785758.html
Copyright © 2011-2022 走看看