浅学Matlab:确定比赛的胜负问题

女朋友突然找我帮她做线代的期末大作业,说是要用 matlab 写篇论文。我倒也一下懵了,虽说我的专业和打代码能沾点边,但我目前也只不熟练地了解 C++一门语言(各位大佬原谅我这个小白大一新生吧),完全没了解过 matlab,不过听说 matlab 对于工科学生还挺实用的,于是趁着这个机会也浅学一下吧。限于 ddl,我的 matlab 学习就从针对这道题入手。

题目

在这里插入图片描述

用 C++来实现

拿到这题倒还感觉挺简单的,至少对于 C++来说是这样。我想着就先用 C++来实现先吧,正好可以理一下思路。(有点南辕北辙,各位看官可跳过)

#include<iostream>
using namespace std;

int main()
{
    int n, **a, tmp, *b, *c, max, max_j;
    cout<<"请输入有几支参赛队伍";
    cin>>n;
    //申请动态空间并赋初值
    a = new int*[n];
    for (int i=0; i<n; i++)
        a[i] = new int [n];
    for (int i=0; i<n; i++)
        for (int j=0; j<n; j++)
            a[i][j]=0;
    //获取数据
    for (int i=0; i<n; i++)
    {
        cout<<"请输入第"<<i+1<<"支队伍战胜的队伍"<<endl;
        cout<<"若战胜多支队伍,请用回车键隔开;若输入已完成,请输入0,然后输入回车;若一支队伍都没战胜,请输入0"<<endl;
        for (int j=0; j<n; j++)
        {
            cin>>tmp;
            if (tmp!=0)
            {
                a[i][j]=tmp;
            }
            else
                break;
        }
    }
/**
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
        {
            cout<<a[i][j]<<' ';
        }
        cout<<endl;
    }
**/
    //获取直接胜数据
    b = new int [n];
    for (int i=0; i<n; i++)
        b[i]=0;
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
        {
            if (a[i][j]!=0)
                b[i]++;
            else
                break;
        }
    }
    //获取间接胜数据
    c = new int [n];
    for (int i=0; i<n; i++)
        c[i]=0;
    for (int i=0; i<n; i++)
    {
        for (int j=0; j<n; j++)
            if (a[i][j]!=0)
                c[i]+=b[a[i][j]-1];//注意,数组中的行数和输入的行数不是一个东西
    }
/**
    for (int i=0; i<n; i++)
        cout<<b[i]<<' ';
    cout<<endl;
    for (int i=0; i<n; i++)
        cout <<c[i]<<endl;
**/
    //排序并输出
    for (int i=0; i<n; i++)
    {
        max = -1;
        max_j = -1;
        for (int j=0; j<n; j++)
        {
            if ((b[j]>max)||(b[j]==max&&c[j]>c[max_j]))
            {
                max = b[j];
                max_j = j;
            }
        }
        cout<<"排名第"<<i+1<<"名的队伍是"<<max_j+1<<endl;
        b[max_j]=-1;
    }
    //删除动态申请的空间
    for (int i=0; i<n; i++)
        delete a[i];
    delete b;
    delete c;
    return 0;
}

这段代码随手写的,大佬们随便笑话就可以了/捂脸。
不过写完 C++后怎么样呢?matlab 可以直接运行 cpp 程序呢?显然不太行。根据搜索引擎,可以通过接口让 matlab 运行 C++程序,但考虑到这就不是 matlab 编程了,也不知道她的老师认不认。至于有没有什么方法可以把 C++直接转换为 matlab 代码,好像也没有(不过把 matlab 代码转换为 C++代码反而是 matlab 软件自带的。
没办法,只能从头一点一点学 matlab,南辕北辙搞了个 C++程序倒也是没办法。强烈安利官方课程,就入门而言比看书看视频强太多了在mathworks官⽹上获取课程

输入命令

基本命令倒也不难。值得注意的是:
1.它可以实时交互,给个命令就返回结果
2.每行代码结尾也不用加分号(事实上分号另有作用,这在以后会介绍)
3.右边的工作区会显示各个变量的信息
4.不用定义变量,需要用某个新变量时直接用就可以了

更详细一点的说明如下:

简单命令

想算 3*5 就直接输入3*5就可以了,系统会自动创建一个ans变量来存储结果15
想把 3*5 这个运算结果给变量 m,不用定义变量可以直接写m = 3*5
至于变量的运算和变量之间的赋值就很简单了,大家看着示例便可以意会了

分号的作用

前面提到 matlab 中的命令不用像 C++中那样每行都要加分号,而且 matlab 会实时对你的命令做出反应,那 matlab 中的行末分号有什么用呢?如何让 matlab 不要实时对你的命令做出反应呢?答案已经暗示的很明显了,那就是在行末加分号可以让 matlab 不要实时对你的命令做出反应,不过在工作区中还是可以看到变量发生了变化。

重新调用以前的命令

这是我觉得最神奇的一点,大家现在按🔼向上键)看看会发现什么。
竟然在这一行出现了之前行的代码!再继续摁向上键,继续出现了更之前的代码!
matlab 突然有意思了起来。

获取变量的值

直接输入变量名再按下enter键就可以了!(好方便)

命名变量

这些都跟 C++中差不多,就不赘述了

保存和加载变量

save可以把工作区中的变量保存到 MAT 文件的 MATLAB 特定格式文件中,比如要把工作区保存到 datafile.mat 文件中,可以直接输入save datafile
load可以从 MAT 文件(就是 save 保存的文件)中加载变量,直接输入load datafile
如果只想要保存或加载部分变量,可以写成load datafile msave datafile m
clear可以将工作区清空,直接输入clear
clc可以清空命令行窗口
想要查看工作区中变量的内容?直接输入变量名就可以了

使用内置函数和常量

pi在 matlab 就代表π,尽管只显示了四位小数但其实他的精度很高
i作为虚数也是 MATLAB 内置的类型之一
使用内置函数时,要用()来括住函数的输入,例如sin(-5)
abs()计算绝对值
eig()计算特征值
sqrt()计算平方根

format long命令可以增加显示精度
format short命令可以减小显示精度

MATLAB 桌面和编辑器

当前文件窗口,命令行窗口,工作区一看就知就不细说了

实时脚本

每次输入命令都有反馈固然方便,但显然如果要编写一个较复杂的程序这样就不太可行了,这时我们可以用到实时脚本
在实时脚本中,在灰色的代码框中可以输入代码,在文本模式中可以添加说明
按下运行键就可以在右侧的区域出现输出结果,把点击某行代码或输上会发现他可以帮我们找到对应的输出或代码
通过分节符还可以将代码分节,来分节运行,剩下的就都可以轻松理解,在这就不赘述了

向量和矩阵

手动输入数组

在 MATLAB 中就算是一个数它也是当作一个 1*1 的数组,不过这个信息好像也没什么用(?
一个数的话单输入就可以了,那么如何创建一个含多个元素的数组呢?可以用方括号来实现:x = [3 5]
创建时需要注意的是:用 ,分隔数值时,还是会把这些数放在同一行,用;时则会换行

创建等间距向量

如果要输入的向量很长,一个一个输入就不太实际。
:运算符可以仅指定起始值和最终值就得到向量,如y = 5:8
:的使用还可以更加灵活,可以指定间距,如x = 20:2:26
有时候不知道间距,但是知道元素的数目,可以使用linspace函数
linspace 函数中,第一个参数是起始值,第二个参数是最终值,第三个参数是元素个数
'可以实现转置(学了线代就一定要用起来 bushi),把行向量转化为列向量
'还可以直接在创建行向量时把它转为列向量,但注意此时要加圆括号

数组创建函数

rand(n)随机获取一个 n 阶方阵
rand(n*m)随机获取一个 n 行 m 列的矩阵
zeros(n*m)创建一个全零矩阵
size(x)获取现有矩阵的大小,甚至可以用rand(size(x))来创建一个与现有矩阵一样大小的随机矩阵

引索和修改数组

对数组进行索引

首先注意其对数组的标号,是从1开始的!和 C++中从 0 开始完全不一样!
如果是要索引向量中的元素,只用输入x = a(2)(索引 a 向量的第 2 个元素)
如果是要索引矩阵中的元素,只用输入x = A(5, 7)(索引 A 矩阵中第 5 行第 7 列元素)
如果要索引某行或列的最后一个元素,只用输入x = A(end, 3)(索引 A 矩阵中第三列的最后一个元素,甚至可以用end-1来表示倒数第二个元素(倒数三四五以此类推

提取多个元素

如果要索引矩阵的某行,只用输入x = A(1, :)(索引A 矩阵中第 1 行全行)
如果要索引矩阵的某列,只用输入x = A(:, 3)(索引A 矩阵中第 3 列全列)
还记得1:3是什么意思吗?这个表达式甚至可以和这块知识点结合起来,例如x = A(1:3, :)(索引 A 矩阵第一到三行的所有元素)
在向量中也可以这样用!x = a(1:3)(索引 a 数组中第一到三个元素)

更改数组中的值

这倒和 C++没有什么区别

数组计算

让数组中所有元素都+1:y = x+1(把 x 数组中所有元素+1 再赋值给 y 对应位置的元素)(当然 1 页可以是任何数)
类似的,也可以让两个相同大小的数组相加,甚至可以相乘或相除
max()函数可以获取某向量中的最大值
可以直接把整个数组放入函数的参数位置,这样的话相当于对数组中的每个元素都进行函数操作y = round(x)(对 x 向量中的每个元素都进行四舍五入操作)
*进行矩阵的乘法
.*进行元素中一一对应的乘法

调用函数

size()函数可以获取矩阵的大小,这在前文也说明过
神奇的是,可以通过方括号来获取多个输出,也就是,可以把获取到的结果分别存入变量[xrow, xcol] = size(x)
max()可以确定向量的最大值及其对应的索引,例如[xMax, idx] = max(x)
有时候只想要函数多个输出值中的一个,就可以使用~来忽略特定输出,例如[~,ivMax] = max(v2)

官方课程中还有获取帮助导入数据绘制数据图的课程,鉴于这对我们解这道题没什么用,我们暂且不学,先学习后面的内容

逻辑数组

关系运算符其他的都一样,就是不等于从!=变成了~=,同时不要忘了它的返回值是01。其他的倒也没有什么其他特别要注意的了。
也可以把数组和一个数进行比较,惊喜不惊喜!这样得到的结果是一个由 0 和 1 组成的数组,里面的 0 和 1 代表着原数组中对应位置的数和给定数比较的结果
还有更秀的操作,甚至可以把逻辑数组作为数组索引!这样的话 MATLAB 会提取所有索引为 true 的数组元素
甚至可以对两个不同的向量使用逻辑索引,例如我要获取 b 向量小于 4 的元素在 a 向量中对应位置的元素可以这样写x = a(b<4)
利用逻辑索引还可以对数组进行重新赋值,比如x(x==999)=1把 x 中等于 999 的所有值都替换为 1
&|是逻辑运算符,对应于 C++中的&&||

决策分支

照例是if else elseif等语句,但要注意的是条件不用用圆括号括起来,也不需要用大括号把代码块括起来,而是用end来表示分支结束

for 循环

同样,条件不用用圆括号括起来,也不需要用大括号把代码块括起来,而是用end来表示分支结束
另外条件可以写成这样x = 1:3意思是循环三次(即从 1,2 到 3),也可以用x = 1:length(density)来对未知长度的向量执行循环


开始解这道题

既然现在已经把程序的逻辑用 C++写出来了,也了解了 Matlab 的基本知识,就让我们开始正式解这道题吧
我们先输入5个球队的胜负情况。那么如何输入呢?我们可以设置一个5*5的矩阵,行的编号代表队的编号,每一行里面的数代表该队打赢的队伍。那么根据题目,输入的矩阵如下:

A = [2, 3, 0, 0, 0;
    3, 4, 5, 0, 0;
    0, 0, 0, 0, 0;
    1, 3, 5, 0, 0;
    1, 3, 0, 0, 0];

然后我们计算每个队直接胜的次数,对应到矩阵A中就是把每行有多少个非零元存入矩阵B中,那我们需要运用嵌套循环,一层来一行行遍历,一层来在每行中一列列遍历:

B = zeros(5*1);
for i=1:5
    for j=1:5
        if (A(i, j)~=0)
            B(i) = B(i)+1;
        end
    end
end

再然后我们需要计算每个队的间接胜的次数,对应到矩阵A中就是我们要把A中第i行中的元素对应的直接胜加和到一起,同样也是通过嵌套循环来实现

C = zeros(5*1);
for i=1:5
    for j=1:5
        if (A(i, j)~=0)
            C(i) = C(i)+B(A(i, j));
        end
    end
end

我们现在已经得到了每队直接胜和间接胜的数据,我们需要把他们排序,那我们再用一个矩阵D来存储。由于排序有两个约束条件,我们可采用简单的循环嵌套来逐次找到当前的第一名并把它更改

D = zeros(5*1);
for i=1:5
    max = -2;
    max_j = -1;
    for j=1:5
        if B(j)>max||(B(j)==max&&C(j)>C(max_j))
            max = B(j);
            max_j = j;
        end
    end
    fprintf('第%d名是第%d队', i, max_j)
    B(max_j) = -1;
end

这样子我们就获得排名顺序了!
至于如何要给 n 支球队排序呢?很简单,只要把 n 都替换成 5 就可以了

A = [2, 3, 0, 0, 0;
    3, 4, 5, 0, 0;
    0, 0, 0, 0, 0;
    1, 3, 5, 0, 0;
    1, 3, 0, 0, 0];
n = 5;
B = zeros(n*1);
for i=1:n
    for j=1:n
        if (A(i, j)~=0)
            B(i) = B(i)+1;
        end
    end
end
C = zeros(n*1);
for i=1:n
    for j=1:n
        if (A(i, j)~=0)
            C(i) = C(i)+B(A(i, j));
        end
    end
end
D = zeros(n*1);
for i=1:n
    max = -2;
    max_j = -1;
    for j=1:n
        if B(j)>max||(B(j)==max&&C(j)>C(max_j))
            max = B(j);
            max_j = j;
        end
    end
    fprintf('第%d名是第%d队\n', i, max_j)
    B(max_j) = -1;
end

如此一来我们只用输入队伍的支数 n 和记录其胜的矩阵我们就可以得到他们的排名了

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在静态方法中使用JdbcTemplate需要注意以下几点: 1. 静态方法中无法直接使用Spring容器中的Bean,因为静态方法是类级别的,而Bean是实例级别的。因此需要手动获取JdbcTemplate实例,可以通过ApplicationContext获取JdbcTemplate实例,或者通过静态变量保存JdbcTemplate实例。 2. 在使用JdbcTemplate时,需要先创建一个JdbcTemplate实例,并设置数据源。数据源可以通过Spring容器注入,或者手动创建。在静态方法中,可以通过静态变量保存JdbcTemplate实例,避免重复创建。 3. 在使用JdbcTemplate操作数据库时,需要注意线程安全问题。JdbcTemplate是线程安全的,但是需要保证JdbcTemplate实例的线程安全,即在多线程环境中需要保证同一JdbcTemplate实例不会被并发访问。 下面是一个示例代码: ``` public class JdbcUtils { private static JdbcTemplate jdbcTemplate; public static void setDataSource(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); } public static void executeSql(String sql) { jdbcTemplate.execute(sql); } } ``` 在上面的代码中,我们通过静态变量保存了JdbcTemplate实例,并提供了一个静态方法setDataSource用于设置数据源。在使用JdbcTemplate时,我们可以直接调用静态方法executeSql执行SQL语句。需要注意的是,这里的executeSql方法是线程安全的,因为JdbcTemplate实例是共享的,并且JdbcTemplate本身是线程安全的。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值