洛谷CF803A Maximal Binary Matrix解析

原题目来源:http://codeforces.com/problemset/problem/803/A


题目描述

You are given matrix with n rows and n columns filled with zeroes. You should put k ones in it in such a way that the resulting matrix is symmetrical with respect to the main diagonal (the diagonal that goes from the top left to the bottom right corner) and is lexicographically maximal.

One matrix is lexicographically greater than the other if the first different number in the first different row from the top in the first matrix is greater than the corresponding number in the second one.

If there exists no such matrix then output -1.

输入格式:

The first line consists of two numbers n  and k ( 1 <= n <= 100 , 0 <= k <= 10^6 ).

输出格式:

If the answer exists then output resulting matrix. Otherwise output -1.

输入输出样例:

输入 #1                                                                   

3 2                       

输出 #1

1 0 0 
0 1 0 
0 0 0 

 大致翻译:

给你一个 n 行 n 列全是 0 的矩阵。 你需要把 k 个 1 放到矩阵中, 保证得到的矩阵相对于主对角线(从左上角到右下角的对角线)是对称的,并且保证这个矩阵的字典序最大。如果不存在这样一个矩阵输出 -1

ps(两个矩阵比较字典序时从第一行向最后一行,每一行从前向后进行比较。)

矩阵字典序的比较如下图所示:

(假定将3个1放入3*3的矩阵中)第一个矩阵字典序小于第二个

               1      0      0                                          1      1      0

               0      1      0                                               0      0

               0      0      1                                          0      0      0                                

题目分析:

从字典序的比较可以看出我们在将k个1放进矩阵时应该优先在行和列中放置并相对主对角线对齐,然后再考虑对角线上的放置。且当k<n^2时不存在将k个1放置在n*n的矩阵放置不下的情况,因此只有在k>n^2时才输出-1,并且题目给的数据范围不大,n*n的矩阵用int型的二维数组就行,而1的放置用递归就可以完成。

递归时我们首先要分析并注意递归的边界:

//函数边界部分
#include <iostream>
#include <cstdio>
using namespace std;
int a[100][100] = { 0 };
int i = 0, j = 0;
int n_i = 0;//当前预处理行
void place(int n, int k)
{
	if (k == 0)//当剩余的k为0时直接返回
	{
		return;
	}
	if (k == 1)//当剩余待填充的1只有1个时在对角线上填充后返回
	{
		a[n_i][n_i] = 1;
		return;
	}
}
//

具体代码(已成功AC):

#include <iostream>
#include <cstdio>
using namespace std;
int a[100][100] = { 0 };
int i = 0, j = 0;
int n_i = 0;//当前预处理行
void place(int n, int k)//将k个1放置在n*n的矩阵中
{
	if (k == 0)
	{
		return;
	}
	if (k == 1)
	{
		a[n_i][n_i] = 1;
	 	return;
	}
	if (k >= 2 * n - 1)//当k>矩阵当前行和列的总数时将该行和列全部填充为1
	{
		for (j = n_i; j < n+n_i; j++)
		{
			a[n_i][j] = 1;
			a[j][n_i] = 1;
		}
		n_i++;//预处理下一行
		return place(n-1, k-(2*n-1));
	}
	else
	{
		for (j = n_i; j < n_i + (k / 2); j++)//假定剩余的k的数量为偶数
		{
			a[n_i][j] = 1;
			a[j][n_i] = 1;
		}
		if (k % 2 == 1)//如果为奇数将少填充的部分补上
		{
			a[n_i][j] = 1;
			a[j][n_i] = 1;
			return place(n, 0);
		}
		else//偶数则对角线填1
		{
			n_i++;
			return place(n,1);
		}
	}
}
int main()
{
	int n, k;
	cin >> n >> k;
	if (k > n * n)//k的个数大于矩阵的总容量时
	{
		cout << -1;
		return 0;
	}
	place(n, k);
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			cout << a[i][j] << " ";
		}
		cout << endl ;
	}
	return 0;
}

 !!!注意在函数的循环中 j 的范围和函数的递归边界,以避免少输出1或者多次重复赋值以及堆栈溢出的情况。如若担心数组越界异常等情况可以扩大数组范围,编者多次提交题目时发现scanf并没有比cin时间快,可能是平台问题,如果超时也可以尝试替换。

编者目前水平一般,如果有更好的代码请多多指教。

张 zjr

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码也是一段汇编代码,它的作用是将d0和d8寄存器中的值相加,然后将结果存储到d1寄存器中,然后进行一些数据存储和比较操作。具体来说: - NOP:这条指令是一个空操作,没有任何作用,仅用于填充空隙。 - MOV d8,d0:这条指令将d0寄存器中的值移动到d8寄存器中。 - NOP:这条指令是一个空操作,没有任何作用,仅用于填充空隙。 - ADDS d1,d0:这条指令将d0和d1寄存器中的值相加,并将结果存储到d1寄存器中。其中ADDS指令表示有符号相加,d1是目标寄存器,d0是源操作数。 - Illegal Instruction:这条指令是一条非法指令,会导致程序崩溃。可能是因为代码中存在错误或者与硬件不兼容导致的。 - ST.A [a1],a5:这条指令将a5寄存器中的值存储到地址a1指向的内存中。其中ST.A指令表示存储一个字节,[a1]是目标操作数,a5是源操作数。 - EQ d15,d0,d8:这条指令将d0和d8寄存器中的值进行比较,如果相等,则将d15寄存器中的值设置为1,否则设置为0。其中EQ指令表示相等,d15是目标寄存器,d0和d8是源操作数。 - Illegal Instruction:这条指令是一条非法指令,会导致程序崩溃。可能是因为代码中存在错误或者与硬件不兼容导致的。 - ADDSC.A a0,a7,d15,0x0:这条指令将d15寄存器的值加上0,然后将结果加到a7寄存器中,并将结果存储回a0寄存器中。其中ADDSC.A指令表示有符号相加,并且加上一个立即数0x0,d15是源操作数,a7是目标寄存器,a0是源操作数。 - J 0x803AC126:这条指令将程序跳转到0x803AC126地址处。其中J指令表示跳转,0x803AC126是目标地址。 - MOV.AA a0,a0:这条指令将a0寄存器中的值移动到a0寄存器中。这条指令的作用是不做任何操作,仅用于填充空隙。 - NOP:这条指令是一个空操作,没有任何作用,仅用于填充空隙。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值