T11 图像旋转
描述
输入一个n行m列的黑白图像,将它顺时针旋转90度后输出。
输入
第一行包含两个整数n和m,表示图像包含像素点的行数和列数。1 <= n <= 100,1 <= m <= 100。
接下来n行,每行m个整数,表示图像的每个像素点灰度。相邻两个整数之间用单个空格隔开,每个元素均在0~255之间。
输出
m行,每行n个整数,为顺时针旋转90度后的图像。相邻两个整数之间用单个空格隔开。
样例输入 3 3 1 2 3 4 5 6 7 8 9 样例输出 7 4 1 8 5 2 9 6 3
以矩阵元素坐标为例:
1,1 1,2 1,3 顺时针旋转后为 2,1 1,1
2,1 2,2 2,3 2,2 1,2
2,3 1,3
所以输出时第一重循环i正着循环每一列,第二重循环j倒着循环每一行,依次输出(j,i)
1 #include<iostream> 2 using namespace std; 3 int n,m,a[101][101]; 4 int main() 5 { 6 cin>>n>>m; 7 for(int i=1;i<=n;i++) 8 for(int j=1;j<=m;j++) 9 cin>>a[i][j]; 10 for(int i=1;i<=m;i++) 11 { 12 for(int j=n;j>=1;j--) 13 cout<<a[j][i]<<' '; 14 cout<<endl; 15 } 16 }
T12 变换的矩阵
描述
有一个N x N(N为奇数,且1 <= N <= 10)的矩阵,矩阵中的元素都是字符。这个矩阵可能会按照如下的几种变幻法则之一进行变幻(只会变幻一次)。
现在给出一个原始的矩阵,和一个变幻后的矩阵,请编写一个程序,来判定原始矩阵是按照哪一种法则变幻为目标矩阵的。
1. 按照顺时针方向旋转90度;
如:
1 2 3 7 4 1
4 5 6 变幻为 8 5 2
7 8 9 9 6 3
2. 按照逆时针方向旋转90度;
如:
1 2 3 3 6 9
4 5 6 变幻为 2 5 8
7 8 9 1 4 7
3. 中央元素不变(如下例中的 5),其他元素(如下例中的3)与“以中央元素为中心的对应元素”(如下例中的7)互换;
如:
1 2 3 9 8 7
4 5 6 变幻为 6 5 4
7 8 9 3 2 1
4. 保持原始矩阵,不变幻;
5. 如果 从原始矩阵 到 目标矩阵 的变幻,不符合任何上述变幻,请输出5
输入
第一行:矩阵每行/列元素的个数 N;
第二行到第N+1行:原始矩阵,共N行,每行N个字符;
第N+2行到第2*N+1行:目标矩阵,共N行,每行N个字符;
输出
只有一行,从原始矩阵 到 目标矩阵 的所采取的 变幻法则的编号。
样例输入 5 a b c d e f g h i j k l m n o p q r s t u v w x y y x w v u t s r q p o n m l k j i h g f e d c b a 样例输出 3
方法1(比较麻烦,但是快用时1ms,时间复杂度n²—4n²):记录下原始矩阵每一种变换情况后的矩阵,然后与目标矩阵对比
1,1 1,2 1,3 顺时针旋转后为 2,1 1,1
2,1 2,2 2,3 2,2 1,2
2,3 1,3
所以记录时第一重循环i正着循环每一列,第二重循环j倒着循环每一行,依次记录a[j][i]
1,1 1,2 1,3 逆时针旋转后为 1,3 2,3
2,1 2,2 2,3 1,2 2,2
1,1 2,1
所以记录时第一重循环i正着循环每一行,第二重循环j倒着循环每一列,依次记录a[i][j]
情况3也就是将整个矩阵旋转180°,所以记录时两重循环都倒着循环
1 #include<iostream> 2 #include<cstdlib> 3 using namespace std; 4 int n; 5 char a[11][11],b[11][11],c[11][11]; 6 void case1() 7 { 8 int x=0,y=0; 9 for(int i=1;i<=n;i++) 10 { 11 x++;y=0; 12 for(int j=n;j>=1;j--) 13 c[x][++y]=a[j][i]; 14 for(int k=1;k<=n;k++) 15 if(c[x][k]!=b[x][k]) 16 return; 17 } 18 cout<<'1'; 19 exit(0); 20 } 21 void case2() 22 { 23 int x=0,y=0; 24 for(int i=n;i>=1;i--) 25 { 26 x++;y=0; 27 for(int j=1;j<=n;j++) 28 c[x][++y]=a[j][i]; 29 for(int k=1;k<=n;k++) 30 if(c[x][k]!=b[x][k]) 31 return ; 32 } 33 cout<<'2'; 34 exit(0); 35 } 36 void case3() 37 { 38 int x=0,y=0; 39 for(int i=n;i>=1;i--) 40 { 41 x++;y=0; 42 for(int j=n;j>=1;j--) 43 c[x][++y]=a[i][j]; 44 for(int k=1;k<=n;k++) 45 if(c[x][k]!=b[x][k]) 46 return; 47 } 48 cout<<'3'; 49 exit(0); 50 } 51 void case4() 52 { 53 for(int i=1;i<=n;i++) 54 for(int j=1;j<=n;j++) 55 if(a[i][j]!=b[i][j]) 56 return; 57 cout<<'4'; 58 exit(0); 59 } 60 int main() 61 { 62 cin>>n; 63 for(int i=1;i<=n;i++) 64 for(int j=1;j<=n;j++) 65 cin>>a[i][j]; 66 for(int i=1;i<=n;i++) 67 for(int j=1;j<=n;j++) 68 cin>>b[i][j]; 69 case1(); 70 case2(); 71 case3(); 72 case4(); 73 cout<<'5'; 74 return 0; 75 }
方法2(代码较短,但慢一点,9ms,时间复杂度,固定4n²):
省去方法1中的记录,直接根据目标矩阵与原矩阵变换后元素的位置关系判断。所以需要判断完所有位置才能出结果
顺时针旋转目标数组b[i][j]对应原数组a[n-j+1][i]
逆时针旋转目标数组b[i][j]对应原数组a[j][n-i+1]
中心对称目标数组b[i][j]对应原数组a[n-i+1][n-j+1]
1 #include<iostream> 2 using namespace std; 3 int n; 4 char a[101][101],b[101][101]; 5 bool p[5]; 6 int main() 7 { 8 cin>>n; 9 for(int i=1;i<=n;i++) 10 for(int j=1;j<=n;j++) 11 cin>>a[i][j]; 12 for(int i=1;i<=n;i++) 13 for(int j=1;j<=n;j++) 14 cin>>b[i][j]; 15 for(int i=1;i<=n;i++) 16 for(int j=1;j<=n;j++) 17 { 18 if(b[i][j]!=a[n-j+1][i]) p[1]=true; 19 if(b[i][j]!=a[j][n-i+1]) p[2]=true; 20 if(b[i][j]!=a[n-i+1][n-j+1]) p[3]=true; 21 if(b[i][j]!=a[i][j]) p[4]=true; 22 } 23 for(int i=1;i<=4;i++) 24 if(!p[i]) 25 { 26 cout<<i;return 0; 27 } 28 cout<<'5'; 29 }
T13 图像模糊处理
描述
给定n行m列的图像各像素点的灰度值,要求用如下方法对其进行模糊化处理:
1. 四周最外侧的像素点灰度值不变;
2. 中间各像素点新灰度值为该像素点及其上下左右相邻四个像素点原灰度值的平均(舍入到最接近的整数)。
输入
第一行包含两个整数n和m,表示图像包含像素点的行数和列数。1 <= n <= 100,1 <= m <= 100。
接下来n行,每行m个整数,表示图像的每个像素点灰度。相邻两个整数之间用单个空格隔开,每个元素均在0~255之间。
输出
n行,每行m个整数,为模糊处理后的图像。相邻两个整数之间用单个空格隔开。
样例输入 4 5 100 0 100 0 50 50 100 200 0 0 50 50 100 100 200 100 100 50 50 100 样例输出 100 0 100 0 50 50 80 100 60 0 50 80 100 90 200 100 100 50 50 100
四舍五入可以用函数round,也可以用printf(”.0lf“,x);
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 int n,m,a[101][101],b[101][101]; 5 int main() 6 { 7 cin>>n>>m; 8 for(int i=1;i<=n;i++) 9 for(int j=1;j<=m;j++) 10 cin>>a[i][j]; 11 for(int i=1;i<=n;i++) 12 for(int j=1;j<=m;j++) 13 { 14 if(i==1||i==n||j==1||j==m) 15 b[i][j]=a[i][j]; 16 else 17 { 18 double r=((double)a[i][j]+a[i-1][j]+a[i+1][j]+a[i][j-1]+a[i][j+1])/5; 19 b[i][j]=round(r); 20 } 21 } 22 for(int i=1;i<=n;i++) 23 { 24 for(int j=1;j<=m;j++) 25 cout<<b[i][j]<<' '; 26 cout<<endl; 27 } 28 }
T14 扫雷游戏地雷数计算
描述
扫雷游戏是一款十分经典的单机小游戏。它的精髓在于,通过已翻开格子所提示的周围格地雷数,来判断未翻开格子里是否是地雷。
现在给出n行m列的雷区中的地雷分布,要求计算出每个非地雷格的周围格地雷数。
注:每个格子周围格有八个:上、下、左、右、左上、右上、左下、右下。
输入
第一行包含两个整数n和m,分别表示雷区的行数和列数。1 <= n <= 100, 1 <= m <= 100。
接下来n行,每行m个字符,‘*’表示相应格子中是地雷,‘?’表示相应格子中无地雷。字符之间无任何分隔符。
输出
n行,每行m个字符,描述整个雷区。若相应格中是地雷,则用‘*’表示,否则用相应的周围格地雷数表示。字符之间无任何分隔符。
样例输入 3 3 *?? ??? ?*? 样例输出 *10 221 1*1
两种思路:1、统计出每个地雷的位置,以地雷为基准,周围8个非地雷的格子+1。预测应该比第二种方法快
2、以每一个格子为基准,枚举周围8个格子。时间复杂度O(8n²)
在此只提供第一种方法的代码
1 #include<iostream> 2 using namespace std; 3 int n,m,b[101][101],cnt; 4 int dx[8]={-1,-1,-1,0,1,1,1,0}; 5 int dy[8]={-1,0,1,1,1,0,-1,-1}; 6 int x[10001],y[10001]; 7 char a[101][101]; 8 int main() 9 { 10 cin>>n>>m; 11 for(int i=1;i<=n;i++) 12 for(int j=1;j<=m;j++) 13 { 14 cin>>a[i][j]; 15 if(a[i][j]=='*') 16 { 17 x[++cnt]=i;y[cnt]=j; 18 } 19 } 20 for(int i=1;i<=cnt;i++) 21 { 22 int xx=x[i],yy=y[i]; 23 for(int j=0;j<8;j++) 24 { 25 int nx=xx+dx[j],ny=yy+dy[j]; 26 if(nx>0&&nx<=n&&ny>0&&ny<=m&&a[nx][ny]!='*') 27 b[nx][ny]++; 28 } 29 } 30 for(int i=1;i<=n;i++) 31 { 32 for(int j=1;j<=m;j++) 33 if(a[i][j]=='*') cout<<'*'; 34 else cout<<b[i][j]; 35 cout<<endl; 36 } 37 }
T15 细菌的繁殖与扩散
描述
在边长为9的正方形培养皿中,正中心位置有m个细菌。假设细菌的寿命仅一天,但每天可繁殖10个后代,而且这10个后代,有两个分布在原来的单元格中,其余的均匀分布在其四周相邻的八个单元格中。求经过n(1≤n≤4)天后,细菌在培养皿中的分布情况。
输入
输入为两个整数,第一个整数m表示中心位置细菌的个数(2 ≤ m ≤ 30),第二个整数n表示经过的天数(1 ≤ n ≤ 4)。
输出
输出九行九列整数矩阵,每行的整数之间用空格分隔。整个矩阵代表n天后细菌在培养皿上的分布情况。
样例输入 2 1 样例输出 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 2 4 2 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
三维数组a[k][i][j]代表第k天后矩阵[i,j]位置的细菌数,每次更新时,由于细菌寿命只有一天,所以新的a[k][i][j]=a[k-1][i][j]*2+a[k-1][ni][nj],ni,nj为[i,j]周围的八个单元格
1 #include<iostream> 2 using namespace std; 3 int m,n; 4 int dx[8]={-1,-1,-1,0,1,1,1,0}; 5 int dy[8]={-1,0,1,1,1,0,-1,-1}; 6 int a[5][10][10]; 7 int main() 8 { 9 cin>>m>>n; 10 a[0][5][5]=m; 11 for(int k=1;k<=n;k++)//枚举每一天 12 { 13 for(int i=1;i<=9;i++) 14 for(int j=1;j<=9;j++)//枚举每个单元格 15 { 16 a[k][i][j]=2*a[k-1][i][j];//留在原单元格的2个 17 for(int l=0;l<8;l++)//周围的8个单元格 18 { 19 int nx=i+dx[l],ny=j+dy[l]; 20 if(nx>0&&nx<=9&&ny>0&&ny<=9) 21 a[k][i][j]+=a[k-1][nx][ny]; 22 } 23 } 24 } 25 for(int i=1;i<=9;i++) 26 { 27 for(int j=1;j<=9;j++) 28 cout<<a[n][i][j]<<' '; 29 cout<<endl; 30 } 31 }
上面的代码是9ms,下面这个是0ms,搞不懂哪里拖延了时间,期待各位的指点
1 #include<bits/stdc++.h> 2 using namespace std; 3 int G[15][15],m,n,a[15][15],dx[]={0,0,1,-1,1,-1,1,-1},dy[]={-1,1,0,0,1,-1,-1,1}; 4 int main() 5 { 6 cin>>m>>n;G[5][5]=m; 7 while(n--) 8 { 9 memset(a,0,sizeof(a)); 10 for(int i=1;i<=9;i++) 11 for(int j=1;j<=9;j++) 12 { 13 a[i][j]+=G[i][j]*2; 14 for(int k=0;k<8;k++) 15 a[i+dx[k]][j+dy[k]]+=G[i][j]; 16 } 17 memcpy(G,a,sizeof(a)); 18 } 19 for(int i=1;i<=9;i++) 20 { 21 for(int j=1;j<=9;j++) 22 cout<<G[i][j]<<' '; 23 cout<<endl; 24 } 25 return 0; 26 }
T16 矩阵石头剪刀布
描述
Bart的妹妹Lisa在一个二维矩阵上创造了新的文明。矩阵上每个位置被三种生命形式之一占据:石头,剪刀,布。每天,上下左右相邻的不同生命形式将会发生战斗。在战斗中,石头永远胜剪刀,剪刀永远胜布,布永远胜石头。每一天结束之后,败者的领地将被胜者占领。
你的工作是计算出n天之后矩阵的占据情况。
输入
第一行包含三个正整数r,c,n,分别表示矩阵的行数、列数以及天数。每个整数均不超过100。
接下来r行,每行c个字符,描述矩阵初始时被占据的情况。每个位置上的字符只能是R,S,P三者之一,分别代表石头,剪刀,布。相邻字符之间无空格。
输出
输出n天之后的矩阵占据情况。每个位置上的字符只能是R,S,P三者之一,相邻字符之间无空格。
样例输入 3 3 1 RRR RSR RRR 样例输出 RRR RRR RRR
a[k][i][j]代表第k天,矩阵[i,j]的字符
枚举每一天每一对格子的情况,因为它只会被能够赢它的字符更新,且能更新它的字符只有一个,所以可以每次在四周找能更新它的字符,找到更新,找不到就保持原状
因为R,S,P互相都有胜负关系,所以每一天每个格子只能被更新一次,所以更新了可以立刻停止对这个格子四周的搜索。例:R遇到P,R在今天结束时更新成P,但今天这个格子遇到R,平局,遇到S,胜利,自己不会被更新
所以确定a[k][i][j]时,要由a[k-1][i-1][j],a[k-1][i][j+1],a[k-1][i+1][j],a[k-1][i][j-1]决定,注意是k-1,即上一天的情况。例:PRS,P可以更新R,R可以更新S,由于枚举的顺序,所以先变成PPS,然后枚举到S时,因为这还是同一天,所以要用原来的R来更新S,而不是用S来更新P
由于a[k][i][j]的情况只与a[k-1][][]有关,所以可以用滚动数组优化空间
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int r,c,n; 5 int dx[4]={-1,0,1,0}; 6 int dy[4]={0,1,0,-1}; 7 char a[2][110][110]; 8 void work(int last/*滚动数组*/,int h/*行*/,int l/*列*/,char win/*目标字符,即可以更新它的字符*/) 9 { 10 int now=(last+1)%2; 11 int ok=0; 12 for(int i=0;i<4;i++) 13 { 14 if(a[last][h+dx[i]][l+dy[i]]==win) ok=1,a[now][h][l]=win; 15 if(ok) break;//更新了便可退出 16 } 17 if(!ok) a[now][h][l]=a[last][h][l]; 18 } 19 int main() 20 { 21 cin>>r>>c>>n; 22 for(int i=1;i<=r;i++) 23 for(int j=1;j<=c;j++) 24 cin>>a[0][i][j]; 25 for(int k=1;k<=n;k++) 26 { 27 memset(a[k%2],'