关于这个练习13,个人认为总体上难度较大,尤其是E题(计算鞍点)以及H题(扫雷)、I题(矩阵交换)、J题(矩阵A*B),不仅思路上想不到,即便是想到了一种可能的思路,要想将这个想法用代码写出来,那也可谓是难如登天。其中E题我觉得是最难想的,因为H题虽然很难,但思路上却不是那么难想;I题(有一个矩阵,要求输出经过k次行变换或列变换后得到的矩阵)虽说麻烦了些,但只要坚持不懈地敲代码,就可以实现题目。J题就是代码上真的很繁琐,需要三重循环,就类似于百钱买百鸡或者是百钱买百笔(之前的练习里有)那样。我已经在之前的练习里讲过这道题,是很经典的一道题,一定要掌握。所以,接下来我会说一说这道题以及从这道题体会出的感悟。
E(计算鞍点)
题目描述 给定一个m*n的矩阵,寻找这个矩阵的鞍点。鞍点指的是矩阵中的一个元素,它是所在行的最大值,并且是所在列的最小值。例如:在下面的例子中(第4行第1列的元素就是鞍点,值为8 )。 
11 3 5 6 9     如果存在鞍点,输出鞍点所在的行、列及其值,如果存在多个,先输出行数更小的,行数相同,先输出列数最小的,如果不存在,输出"No"。
12 4 7 8 10 
10 5 6 9 11 
8 6 4 7 2 
15 10 11 20 25  
输入描述: 第1行:2个数m,n,对应矩阵的行列数量(2<=m, n<=100) 第2-m+1行:每行n个数中间用空格分隔(0<=m(i,j) <=1000) 
输出描述: 如果存在t个鞍点,输出共t行,每行3个数,对应所在的行、列及其值,如果不存在鞍点,输出"No"                                                                                                                                              
                                                                                                                                                                                                                                                                                                                             
可能会有人疑惑了,怎么会有多个鞍点存在呢?这就是这道题的有意思之处了,也是我想要提一下这道题的原因之一。你是说某个数是矩阵某行或某列的最大值或最小值,但你说如果存在这样的矩阵:3 3  
                                                                                                                                                                                                                                                                                                                             4 4 
是不是两个3都是所在行的最大值并且是所在列的最小值?所以,如果将这样一个矩阵输入运行,就会出现这样的结果:                                                                                                                                                                      

所以,输出描述里说的没有错误,但是如果你不看这个输出描述,理论上你还是有可能做对的,甚至会更快AC该题。
我写的代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    int n,m,i,j,flag=0;
    int c[101][101];
    int d[101]={0};
    int e[101]={0};
    cin>>n>>m;
    for(i=1;i<=n;i++)
    {
    for(j=1;j<=m;j++)
    {
    cin>>c[i][j];
    }
    }
    for(i=1;i<=n;i++)
    {
        int f=0;
        for(j=1;j<=m;j++)
        f=max(f,c[i][j]);
        d[i]=f;
    }
    for(i=1;i<=m;i++)
    {
        int g=1000;
        for(j=1;j<=n;j++)
        g=min(g,c[j][i]);
        e[i]=g;
    }
    for(i=1;i<=n;i++)
    {
    for(j=1;j<=m;j++)
    {
     if(c[i][j]==d[i] &&c[i][j]==e[j])
     {
         flag=1;
         cout<<i<<" "<<j<<" "<<c[i][j]<<endl;
     }
    }
    }
    if(flag==0) cout<<"No"<<endl;
    return 0;
}
我的思路就是定义一个二维数组用于存储矩阵,两个一维数组分别用于记录每行的最大值和每列的最小值,最后在二维数组中查找符合条件的元素,将每行最大的元素和每列的最小元素在二维数组中查找其在二维数组中的位置,如果每行最大的元素和每列的最小元素刚好为同一个元素,则状态变量flag为1,并输出其在矩阵中的横坐标i和其纵坐标j并输出该元素,否则若flag为0,说明不存在鞍点。

或者像下面的代码一样,定义三个矩阵,先将max矩阵和min矩阵都初始化为输入的矩阵值,之后定义一个变量maxN等于宏定义中设置的初值-1(因为题干说所有元素均大于0),之后对于每一行,都找到其中的最大值,并更新 max 矩阵。如果该行的最大值不是当前最大值,则将 max 矩阵中的相应位置设为最大值。这样就设置好了max矩阵,之后找到每列的最小值的部分与之前找到每行的最大值的逻辑相似,但它是针对列进行的。遍历整个矩阵,如果某个位置 max值不等于 MAX 且其 min 值不等于 MIN,则说明该位置是鞍点,状态变量flag为1,并输出该位置的横坐标i和纵坐标j以及它的值。如果没有这样的位置,则输出 "No"。
#include<iostream>
#define MAX -1
#define MIN 1000000
using namespace std;
int main()
{
    int i,j,n,m,maxN,minN,flag=0,x,y;
    int a[101][101],max[101][101],min[101][101];
    cin>>n>>m;

    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            cin>>a[i][j];
            max[i][j]=min[i][j]=a[i][j];
        }
    }
    for(i=1;i<=n;i++){
        maxN=MAX;
        for(j=1;j<=m;j++){
            if(maxN<a[i][j])maxN=a[i][j];
        }
        for(j=1;j<=m;j++){
            if(maxN!=max[i][j])max[i][j]=MAX;
        }
    }
    for(i=1;i<=m;i++){
        minN=MIN;
        for(j=1;j<=n;j++){
            if(minN>a[j][i])minN=a[j][i];
        }
        for(j=1;j<=n;j++){
            if(minN!=min[j][i])min[j][i]=MIN;
        }
    }
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++){
         if(max[i][j]!=MAX&&min[i][j]!=MIN){
             cout<<i<<" "<<j<<" "<<max[i][j]<<endl;
             flag=1;
         }
      }
    }
    if(flag==0)cout<<"No\n";
    return 0;
}
总之,练习13主要是训练我们关于面向过程的设计所必须拥有的逻辑和方法,这在之后的学习中也是必不可少的。