原题目来源: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 1 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