蓝桥杯——趣味数组问题二(2017.2.14)

一、矩阵转置 -->行变列,列变行

        以下情景中设矩阵最大为20*20,即在此范围内保存操作前和操作后矩阵。

1. 方阵(N*N矩阵)转置

源代码:采用“就地转置”方法,不使用新数组,对原数组上下三角部分进行元素交换操作

#include <stdio.h>
#define maxn 20
void Input(int a[][maxn],int N)
{
	int i,j;
	for(i=0;i<N;i++)
		for(j=0;j<N;j++)
			scanf("%d",&a[i][j]);
}
void Reverse(int a[][maxn],int N)
{
	int i,j;
	int t;
	for(i=1;i<N;i++)
	{
		for(j=0;j<i;j++)
		{
			t=a[i][j];
			a[i][j]=a[j][i];
			a[j][i]=t;
		}
	}
}
void Output(int a[][maxn],int N)
{
	int i,j;
	for(i=0;i<N;i++)
	{
		for(j=0;j<N-1;j++)
			printf("%d ",a[i][j]);
		printf("%d\n",a[i][N-1]);
	}
}
int main()
{
	int a[maxn][maxn],N;
	while(scanf("%d",&N)!=EOF)
	{
		Input(a,N);
		Reverse(a,N);
		Output(a,N);
	}
	return 0;
} 
程序截图:


2. 普通矩阵转置

源代码:借助一个新数组,行列互换

#include <stdio.h>
#define maxn 20
void Input(int a[][maxn],int M,int N)
{
	int i,j;
	for(i=0;i<M;i++)
		for(j=0;j<N;j++)
			scanf("%d",&a[i][j]);
}
void Reverse(int a[][maxn],int b[][maxn],int M,int N)
{
	int i,j;
	for(i=0;i<M;i++)
	{
		for(j=0;j<N;j++)
		{
			b[j][i]=a[i][j];
		}
	}
}
void Output(int b[][maxn],int M,int N)
{
	int i,j;
	for(i=0;i<N;i++)
	{
		for(j=0;j<M-1;j++)
			printf("%d ",b[i][j]);
		printf("%d\n",b[i][M-1]);
	}
}
int main()
{
	int a[maxn][maxn],M,N;
	int b[maxn][maxn]={0};
	while(scanf("%d %d",&M,&N)!=EOF)
	{
		Input(a,M,N);
		Reverse(a,b,M,N);
		Output(b,M,N);
	}
	return 0;
} 
程序截图:


二、矩阵旋转:找对应位置对应元素间的关系(以下两例旋转方向为顺时针)

1. 输入N(1<N<=20)及一个N*N矩阵,输入旋转角度p(p=0, 90, 180, 270),输出对应的旋转矩阵

源代码:

#include <stdio.h>
#define maxn 20
int a[maxn][maxn];
int b[maxn][maxn]; 
void Init(int a[][maxn],int b[][maxn],int n)            //初始化方阵 
{
	int i,j;
	for(i=0;i<maxn;i++)
	{
		for(j=0;j<maxn;j++)
		{
			a[i][j]=0;
			b[i][j]=0;
		}
	}
}
void Input(int a[][maxn],int n)
{
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
			scanf("%d",&a[i][j]);
	}
}
void Output(int a[][maxn],int b[][maxn],int angle,int n)
{
	int i,j;
	int flag=1;
	switch(angle)                            //根据输入的旋转角度旋转矩阵 
	{
		case 0:
		{
			for(i=0;i<n;i++)
			{
				for(j=0;j<n;j++)
					b[i][j]=a[i][j];
			}
			break;
		}
		case 90:
		{
			for(i=0;i<n;i++)
			{
				for(j=0;j<n;j++)
					b[i][j]=a[n-1-j][i];
			}
			break;
		}
		case 180:
		{
			for(i=0;i<n;i++)
			{
				for(j=0;j<n;j++)
					b[i][j]=a[n-1-i][n-1-j];
			}
			break;
		}
		case 270:
		{
			for(i=0;i<n;i++)
			{
				for(j=0;j<n;j++)
					b[i][j]=a[j][n-1-i];
			}
			break;
		}
		default:
		{
			printf("Error!\n");
			flag=0;
			break;
		}
	}
	if(flag==1)                              //仅输入符合要求时输出旋转后矩阵 
	{
		for(i=0;i<n;i++)
		{
			for(j=0;j<n-1;j++)
				printf("%d ",b[i][j]);
			printf("%d\n",b[i][n-1]);
		}
	}
}
int main()
{
	int n,angle;
	while(scanf("%d",&n)!=EOF)
	{
		Init(a,b,n);
		Input(a,n);
		scanf("%d",&angle);
		Output(a,b,angle,n);
	}
	return 0;
}
程序截图:


2. 输入N(1<N<=20)及两个N*N矩阵,问第一个矩阵旋转多少度后与第二个矩阵相等?输出这个角度。如不能实现上述功能,输出“-1”

源代码:

#include <stdio.h>
#define maxn 20
int a[maxn][maxn];
int b[maxn][maxn]; 
void Init(int a[][maxn],int b[][maxn],int n)            //初始化方阵 
{
	int i,j;
	for(i=0;i<maxn;i++)
	{
		for(j=0;j<maxn;j++)
		{
			a[i][j]=0;
			b[i][j]=0;
		}
	}
}
void Judge(int a[][maxn],int b[][maxn],int n)          //求旋转角度 
{
	int i,j,angle=-1;
	int flag1=1,flag2=1,flag3=1,flag4=1;
	for(i=0;i<n;i++)	
	{
		for(j=0;j<n;j++)
		{
			if(a[i][j]!=b[i][j])
			{
				flag1=0;
				break;			
			}
		}
	}
	if(flag1==1)
		angle=0;
	for(i=0;i<n;i++)	
	{
		for(j=0;j<n;j++)
		{
			if(a[i][j]!=b[j][n-i-1])
			{
				flag2=0;
				break;			
			}
		}
	}
	if(flag2==1)
		angle=90;
	for(i=0;i<n;i++)	
	{
		for(j=0;j<n;j++)
		{
			if(a[i][j]!=b[n-1-i][n-1-j])
			{
				flag3=0;
				break;			
			}
		}
	}
	if(flag3==1)
		angle=180;
	for(i=0;i<n;i++)	
	{
		for(j=0;j<n;j++)
		{
			if(a[i][j]!=b[n-1-j][i])
			{
				flag4=0;
				break;			
			}
		}
	}
	if(flag4==1)
		angle=270;
	printf("%d\n",angle);
}
void Input(int a[][maxn],int n)
{
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
			scanf("%d",&a[i][j]);
	}
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		Init(a,b,n);
		Input(a,n);
		Input(b,n);
		Judge(a,b,n);
	}
	return 0;
}
程序截图:


三、几个趣味"填数"问题

1. 将1~6 6个数字填入2行3列的表格中,要求每一列右边的数字比左边的数字大且每一行下面的数字比上面的数字大。编程求出按此要求填表的所有方案及方案总数。

【分析】此问题看似是二维数组问题,其实可将这6个元素看做一个一维数组中的元素。根据题意,1与6分别是这个一维数组中的第一个和最后一个元素,然后分析2~5这4个元素的位置:显然a[0]=1 a[5]=6,且

              a[0]    a[1]    a[2]

              a[3]    a[4]    a[5]

        a[1]>a[0](a[1]的取值从a[0]+1开始试探,最大不超过5);

        a[2]>a[1](a[2]的取值从a[1]+1开始试探,最大不超过5);

        a[3]>a[0](a[3]的取值从a[0]+1开始试探,最大不超过5);

        注意a[4]>a[3]且a[4]>a[1],因此a[4]的取值从min{a[1]+1, a[3]+1}开始试探,最大不超过5)

        因此可构造四重循环枚举a[1]~a[4]的所有可能取值,注意2~5不能重复

源代码:

#include <stdio.h>
int count=0;                                 //全局变量 记录方案数
int Judge(int a[])                           //判断a[1]~a[4]的取值是否有重复 
{
	int i,j;
	int flag=1;
	for(i=1;i<=4;i++)
	{
		for(j=i+1;j<=4;j++)
		{
			if(a[i]==a[j])
			{
				flag=0;
				break;
			}
		}
	}
	return flag;
}
void Output(int a[])                         //打印符合条件的方案 
{
	int i;
	for(i=0;i<6;i++)
	{
		if((i+1)%3==0)
			printf("%d\n",a[i]);
		else
			printf("%d ",a[i]);
	}
	printf("\n");
	count++;
}
int main()
{
	int a[6]={1,2,3,4,5,6};
	for(a[1]=a[0]+1;a[1]<=6;a[1]++)
	{
		for(a[2]=a[1]+1;a[2]<=5;a[2]++)
		{
			for(a[3]=a[0]+1;a[3]<=5;a[3]++)
			{
				for(a[4]=((a[1]>a[3]) ? (a[1]+1) : (a[3]+1));a[4]<=5;a[4]++)
				{
					if(Judge(a))
						Output(a);
				}
			}
		}
	}
	printf("count=%d\n",count); 
	return 0;
} 
程序截图:


2. 魔方阵


【分析】魔方阵的生成方法:

Step 1. 第0行中间置1,对从2开始的其余n^2-1个元素按下列规则存放

Step 2. 假定当前数的下标为(i, j),则下一个数的存放位置为当前位置右上方,即下标(i-1, j+1)处

Step 3. 若当前数在第0行,即i-1<0,则将下一个数放在最后一行的下一列上,即下标(n-1, j+1)处

Step 4. 若当前数在最后一列,即j+1>n-1,则将下一个数放在上一行的第一列上,即下标(i-1, 0)处

Step 5. 若当前数的下一个数的位置已有数填入(即当前数是n的倍数),则将下一个数直接放在当前位置正下方,即下标(i+1, j)处

源代码:

#include <stdio.h>
#define maxn 20
int a[maxn][maxn];                    
void Init(int a[][maxn],int n)            //初始化魔方阵 
{
	int i,j;
	for(i=0;i<maxn;i++)
		for(j=0;j<maxn;j++)
			a[i][j]=0;
}
void Setnum(int a[][maxn],int n)          //填数 
{
	int i=0,j=(n-1)/2;
	int prei,prej;                        //prei与prej保存原始i与j的值 
	int num=2;
	a[i][j]=1;                            //确定1的位置,随后从2开始填数 
	while(num<=n*n)
	{
		prei=i,prej=j;
		i-=1;                             //找下一个元素的填空位置 
		j+=1;
		if(i<0)                           //边界处理 
			i=n-1;
		if(j==n)
			j=0;
		if(a[i][j]!=0)                    //下一元素的填空位置非空,将下一元素填入当前元素下方 
		{
			a[prei+1][prej]=num;
			i=prei+1;
			j=prej;
		}
		else                              //否则填入填空位置 
			a[i][j]=num;
		num++;                            //准备填下一个元素 
	} 
}
void Output(int a[][maxn],int n)          //打印n阶魔方阵 
{
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n-1;j++)
			printf("%d ",a[i][j]);
		printf("%d\n",a[i][n-1]);
	}
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		Init(a,n);                        //填数前注意初始化
		if(n<=0 || n%2==0)                //n为非正数或偶数时,打印错误信息 
			printf("Error!\n");
		else
		{
			Setnum(a,n);
			Output(a,n);
		}
	}
	return 0;
}
程序截图:


3. 蛇形填数

        在n*n方阵里填入1, 2, … , n*n,要求填成蛇形。例如n=4时方阵为:

        10 11 12 1

        9 16 13 2

        8 15 14 3

        7 6 5 4

        n=3时方阵为:

        7 8 1

        6 9 2

        5 4 3

        输入方阵阶数n(1<=n<20),输出n阶蛇形矩阵。

源代码:

#include <stdio.h>
#define maxn 20
int a[maxn][maxn];
void Init(int a[][maxn],int n)            //初始化方阵 
{
	int i,j;
	for(i=0;i<maxn;i++)
		for(j=0;j<maxn;j++)
			a[i][j]=0;
}
void Setnum(int a[][maxn],int n)          //填数
{
	int i=0,j=n-1;                        //填空起始点 
	int num=2;
	a[i][j]=1;                            //第一个元素(1)填到起始点位置 
	while(num<=n*n)                       //循环填数过程(按照下左上右的顺序) 
	{
		while(i+1<n && a[i+1][j]==0)      //down 
			a[++i][j]=num++;
		while(j-1>=0 && a[i][j-1]==0)     //left 
			a[i][--j]=num++;
		while(i-1>=0 && a[i-1][j]==0)     //up 
			a[--i][j]=num++;
		while(j+1<n && a[i][j+1]==0)      //right 
			a[i][++j]=num++;
	}                                     //一次循环结束后,若没有填满,继续上述过程 
}
void Output(int a[][maxn],int n)          //打印n阶蛇形矩阵
{
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<n-1;j++)
			printf("%d ",a[i][j]);
		printf("%d\n",a[i][n-1]);
	}
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		Init(a,n);
		Setnum(a,n);
		Output(a,n);
	}
	return 0;
}
程序截图:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值