【矩阵模拟】

知识框架

No.0 筑基

请先学习下知识点,道友!
题目知识点大部分来源于此:

No.1 字符矩阵模拟

题目来源:LeetCode-6. N 字形变换

题目描述:

6. N 字形变换

题目思路:

题目代码:

class Solution {
public:
    string convert(string s, int numRows) {
        int n = s.length(), r = numRows;
        //首先判断极致情况只有一行or只有一列的话
        if (r == 1 || r >= n) {
            return s;
        }

        // 一个周期有t个字符数量
        int t = r + t - 2;
        // 每个周期占据的列数量 r-1 列
        int c = (n + t - 1) / t * (r - 1);
        vector<string> mat(r, string(c, 0));
        int x=0,y=0;
        for (int i = 0; i < n; ++i) {
            mat[x][y] = s[i];
            if (i % t < r - 1) {
                ++x; // 向下移动
            } else {
                --x;
                ++y; // 向右上移动
            }
        }
        string ans;
        for (auto row : mat) {
            for (char ch : row) {
                if (ch) {
                    ans += ch;
                }
            }
        }
        return ans;
    }
};

题目来源:PTA-L1-002 打印沙漏

题目描述:
在这里插入图片描述

题目思路:

思路怎么说呢:找规律吧

题目代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 10010
int n,m,k,g,d;
int x,y,z;
char ch;
vector<int>v[N];

int main() {
    cin>>n>>ch;
    //h 为上面的行数==下面的行数。
    //累加规律:1行有1个,2行有4个,3行有9个。即几行和为几平方。
    //该行规律:1行有1个,2行有3个,3行有5个。2*i-1;
    int shang = (n+1)/2;
    int h=sqrt(shang);
    for(int i=h;i>=1;i--){
        for(int j=1;j<=h-i;j++)cout<<" ";
        for(int j=1;j<=2*i-1;j++)cout<<ch;
        cout<<endl;
    }
    
    for(int i=2;i<=h;i++){
        for(int j=1;j<=h-i;j++)cout<<" ";
        for(int j=1;j<=2*i-1;j++)cout<<ch;
        cout<<endl;
    }

    cout<<n-(2*h*h-1)<<endl;
	return 0;
}

题目来源:PTA-L1-015 跟奥巴马一起画方块

题目描述:
在这里插入图片描述

题目思路:

题目代码:

//对于N要进行适应性的更改,对于字段错误
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,k,g,d;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int main() {
    cin>>n>>ch;
    int h=0;
    if(n%2==0){
        h=n/2;
    }else{
        h=n/2+1;
    }
    for(int i=1;i<=h;i++){
        for(int j=1;j<=n;j++){
            cout<<ch;
        }
        cout<<endl;
    }


	return 0;
}

题目来源:PTA-L1-039 古风排版

题目描述:
在这里插入图片描述

题目思路:

题目代码:

//    char a[N][N]; 注意是 char



#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 10010
int n,m,k,g,d;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int main() {
    cin>>n;
    getchar();
    getline(cin,str);
    int len=str.size();
    int lie=len%n==0?len/n:len/n+1;
    int a=0;
    char cc[105][105];
    for(int i=lie;i>=1;i--){
        for(int j=1;j<=n;j++){
             //因为a比需要的大一
            //str[0]开始的,所以【a】最大为length-1;即当【】内最大时,a++之后 a==length
            if(a<len){
                cc[j][i]=str[a++];
            }else{
                cc[j][i]=' ';
            }
        }
    }
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=lie;j++){
            cout<<cc[i][j];
        }
        cout<<endl;
    }
	return 0;
}

题目来源:PTA-L1-054 福到了

题目描述:
在这里插入图片描述

题目思路:

题目代码:

//这道题主要考察吃回车。。。
//在使用c=getchar()的时候要特别注意。。。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 105
int n,m,k,g,d;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int main() {
    char a[N][N],b[N][N];
    cin>>ch>>n;
    char c;
    getchar();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            c=getchar();
            a[i][j]=c;
        }
        getchar();
    }
    int flag=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            b[i][j]=a[n-i+1][n-j+1];
            if(a[i][j]!=b[i][j]){
                flag=1;
            }
        }
    }
    if(flag==0){
        cout<<"bu yong dao le"<<endl;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(b[i][j]=='@'){
                cout<<ch;
            }else{
                cout<<b[i][j];
            }
        }
        cout<<endl;
    }
	return 0;
}

题目来源:蓝桥杯-2013省赛-打印十字图

题目描述:

在这里插入图片描述

题目思路:

题目代码:

在这里插入代码片

题目来源:蓝桥杯-2015省赛-空心菱形

题目描述:
在这里插入图片描述

题目思路:

题目代码:

import java.util.*;
public class Main
{
    
    static String pr(int m, int n)
    {
        String s = "";
        for(int i=0; i<n; i++) s += ".";
        for(int i=0; i<m; i++) s = "*" + s + "*";
        return s;
    }
    
    static void f(int n)
    {
        String s = pr(1,n*2-1) + "\n";
        String s2 = s;
            
        for(int i=1; i<n; i++){
            s = pr(i + 1,2 * (n - i)  - 1) + "\n";
            s2 = s + s2 + s; 
        }
        
        System.out.print(s2);
    }
    
    public static void main(String[] args)
    {
        f(9);
    }
}

No.2 数字矩阵

题目来源:PTA-L1-048 矩阵A乘以B

题目描述:
在这里插入图片描述

题目思路:

题目代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 1001
int n,m,k,g,d;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int main() {
    int ah,al,bh,bl;
    int a[N][N],b[N][N];
    cin>>ah>>al;
    for(int i=1;i<=ah;i++){
        for(int j=1;j<=al;j++){
            cin>>a[i][j];
        }
    }
    cin>>bh>>bl;
    for(int i=1;i<=bh;i++){
        for(int j=1;j<=bl;j++){
            cin>>b[i][j];
        }
    }
    if(al!=bh){
        cout<<"Error: "<<al<<" != "<<bh<<endl;
    }else{
        cout<<ah<<" "<<bl<<endl;
        for(int i=1;i<=ah;i++){
            for(int j=1;j<=bl;j++){
                int sum=0;
                for(int k=1;k<=al;k++){
                    sum=sum+a[i][k]*b[k][j];
                }
                if(j==1)cout<<sum;
                else cout<<" "<<sum;
            }
            cout<<endl;
        }
    }
	return 0;
}

题目来源:PTA-L1-049 天梯赛座位分配

题目描述:
在这里插入图片描述

题目思路:

这个的矩阵模拟就比较复杂了

题目代码:

//记住N为大于100的但是不能太大
//记住那个 j<=num[i]
#include<bits/stdc++.h>
using namespace std;
int num[111];//记录每个学校的队伍数量
int pos[111][11][11];//i学校j队伍中k队员的位置
int maxx,pre;//maxx记录学校中队伍数量的最大值,pre记录上一个被编号的学校
int x;//记录编号
int main()
{
    int n;//学校数量
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>num[i];//每个学校的队伍数量
        maxx=max(maxx,num[i]);//记录最大队伍数量
    }
    for(int j=1; j<=maxx; j++) //以最大队伍数量为上界,为了让每个人都能在这个循环里添加上位置
    {
        for(int k=1; k<=10; k++)//循环每个队员
        {
            for(int i=1; i<=n; i++)//遍历学校开始编号
            {
                if(j<=num[i])//如果当前的队伍数量j小于等于当前学校的队伍数量,说明可以编号,否则不可以,因为该学校里没有队员可以被编号了,都编完号了
                {
                    if(pre==i)//相邻学校的两个队员必须隔位就坐
                        x+=2;
                    else
                        x++;//不是同一个学校的,连续编排
                    pos[i][j][k]=x;//特别有意思的循环,i学校j队伍中k队员的编号就是x
                    pre=i;//记录上一个被编号的学校
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        cout<<"#"<<i<<endl;
        for(int j=1;j<=num[i];j++)
        {
            for(int k=1;k<=10;k++)
            {
                if(k<=9)
                    cout<<pos[i][j][k]<<" ";
                else
                    cout<<pos[i][j][k]<<endl;
            }
        }
 
    }
    return 0;
 
}

题目来源:PTA-L1-072 刮刮彩票

题目描述:
在这里插入图片描述

题目思路:

题目代码:

#include<iostream>
using namespace std;
int x,y,k;
int main(){
    int a[4][4],value[25]={0,0,0,0,0,0,10000,36,720,360,80,252,108,72,54,180,72,180,119,36,306,1080,144,1800,3600};
    int ix=0,iy=0;
    int book[15]={0};
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
            cin>>x;
            if(x==0){
                ix=i;
                iy=j;
            }else{
                a[i][j]=x;
                book[x]=1;
            }
        }
    }
    for(int i=1;i<=9;i++){
        if(book[i]==0){
            a[ix][iy]=i;
        }
    }
    for(int i=0;i<3;i++){
        cin>>x>>y;
        cout<<a[x][y]<<endl;
    }
    cin>>k;
    int sum=0;
    if(k<=3){
        sum=a[k][1]+a[k][2]+a[k][3];
        cout<<value[sum]<<endl;
    }else if(k<=6){
        sum=a[1][k-3]+a[2][k-3]+a[3][k-3];
        cout<<value[sum]<<endl;
    }else if(k==7){
        sum=a[1][1]+a[2][2]+a[3][3];
        cout<<value[sum]<<endl;
    }else if(k==8){
        sum=a[3][1]+a[2][2]+a[1][3];
        cout<<value[sum]<<endl;
    }
    
    return 0;
} 

题目来源:PTA-L1-087 机工士姆斯塔迪奥

题目描述:
在这里插入图片描述

题目思路:

题目代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 505
int n,m,k,g,d;
int x,y,z;
char ch;
string str;
vector<int>v[N];
#define PII pair<int,int>


	
int main()
{
    cin>>n>>m>>k;
    int map[n+1][m+1]={0};
    while(k--){
        cin>>x>>y;
        if(x==1){
            for(int i=1;i<=n;i++)map[i][y]=1;
        }else{
            for(int j=1;j<=m;j++)map[y][j]=1;
        }
    }
    int res=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(map[i][j]==0)res++;
        }
    }
 	cout<<res<<endl;
    return 0;
}

题目来源:PTA-L2-028 秀恩爱分得快

题目描述:
在这里插入图片描述

题目思路:

题目代码:

思路:用一个二维数组g来存储在同一张照片的不同人之间的亲密度,maxn来记录和A和异性的最大亲密度和B和异性的最大亲密度,因为题目要求按他们编号的绝对值递增输出,所以我们采用set分别存储男性和女性,最后遍历输出就行了

//注意一定要将cin>>str的转化为abs(stoi(str));
注:stoi是将string类型转换成int//1010 1000 1001
//这个1010会超时,1001不会超时。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
#include<vector>
 
using namespace std;
#define N 1010
int n,m,k;
int x,y,z;
char ch;
string str;
int main() {
    cin>>n>>m;
    double g[N][N]={0.0};
    double maxx[N]={0};
    set<int>A,B;
    for(int i=0;i<m;i++){
        cin>>k;
        vector<int>a;
        vector<int>b;
        for(int j=0;j<k;j++){
            cin>>str;
            int num=abs(stoi(str));
            if(str[0]=='-'){
                a.push_back(num);
                A.insert(num);
            }else{
                b.push_back(num);
                B.insert(num);
            }
        }
        for(auto p:a){
            for(auto q:b){
                g[q][p]=g[p][q]+=1.0/k;
                maxx[p]=max(maxx[p],g[p][q]);
                maxx[q]=max(maxx[q],g[p][q]);
            }
        }
    }
    string s1,s2;
    cin>>s1>>s2;
    x=abs(stoi(s1));
    y=abs(stoi(s2));
    if(maxx[x]==g[x][y]&&maxx[y]==g[x][y]){
        cout<<s1<<" "<<s2<<endl;
        return 0;
    }
    //下面对于s1;
    if(s1[0]=='-'){
        for(auto i:B){
            if(maxx[x]==g[x][i]){
                cout<<s1<<" "<<i<<endl;
            }
        }
    }else{
        for(auto i:A){
            if(maxx[x]==g[x][i]){
                cout<<s1<<" -"<<i<<endl;
            }
        }
    }
    
    
    //下面对于s2;
    if(s2[0]=='-'){
        for(auto i:B){
            if(maxx[y]==g[y][i]){
                cout<<s2<<" "<<i<<endl;
            }
        }
    }else{
        for(auto i:A){
            if(maxx[y]==g[y][i]){
                cout<<s2<<" -"<<i<<endl;
            }
        }
    }
	return 0;
}

题目来源:蓝桥杯-2022省赛-统计子矩阵

题目描述:
在这里插入图片描述

题目思路:

1使用前缀和+滑动窗口 ,但是这里是二维矩阵,所以要先计算出纵向的前缀和,a[i][j]表示前i行第j列之和
2然后遍历上边界i和下边界ii,再这个上下边界内使用滑动窗口,由于前面维护了纵向前缀和,所以转化成类似一维的滑动窗口。
3滑动窗口【l,r】:遍历右端点,根据区间和调整左端点,如果区间和大了,左端点右移。注意区间和也要移除左端点,直到找到满足的区间,区间大小r-l+1就是以r为右端点的满足条件子矩阵个数,累加即可

题目代码:

#include <iostream>
using namespace std;
const int maxn = 501;
int a[maxn][maxn];
long long ans = 0;
int main()
{
// 请在此输入您的代码
int n,m,k;
cin >> n >> m >> k;

for(int i = 1; i <= n ; i++)
{
 for(int j = 1; j <= m; j++)
 {
   cin >> a[i][j];
   //为了后面计算方便,维护纵向前缀和
   //a[i][j]表示前i行第j列之和
   a[i][j] += a[i-1][j];
 }
}
//遍历上边界和下边界

for(int i = 1; i <= n; i++)//遍历上边界
{
 for(int ii = i; ii <= n; ii++)//遍历下边界
 {
   int l = 1, r = 1;//滑动窗口的左右端点
   int sum = 0;//区间前缀和:[l,r]区间的累计和
   for(r = 1; r <= m; r++)//遍历右端点,根据区间和调整左端点
   {
     sum += a[ii][r] - a[i-1][r];//加上右端点处的和
     while(sum > k)//区间和了,左端点右移,区间变小
     {
       sum -= a[ii][l] - a[i-1][l];//减去移出去的左端点处的和
       l++;
     }
     ans += r - l + 1;//方法数就是找到的区间大小累加
   }
 }
}
cout << ans << endl;
return 0;
}

题目来源:蓝桥杯-第十四届模拟-第一期 最小矩阵

题目描述:
在这里插入图片描述

题目思路:

枚举起点与终点的位置,寻找和为 2022 时最小的元素个数
二维前缀和获取子矩阵和的复杂度为 O(1)

题目代码:

// 答案:12
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int n = 101;
int a[n][n];

void init() {
    a[1][1] = 1;
    // 构建初始矩阵
    for (int i = 1; i < n; i++) {
        for (int j = 1; j < n; j++) {
            if (i > 1) a[i][j] = a[i - 1][j] + 1;
            else if (j > 1) a[i][j] = a[i][j - 1] + 2;
        }
    }
    // 构建前缀和
    for (int i = 1; i < n; i++) {
        for (int j = 1; j < n; j++) {
            a[i][j] += a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1];
        }
    }
}

// 获取 [i][j] 到 [x][y] 之间子矩阵的和
int getSum(int i, int j, int x, int y) {
    return a[x][y] - a[x][j - 1] - a[i - 1][y] + a[i - 1][j - 1];
}

signed main() {
    init();
    int ans = n * n;
    for (int i = 1; i < n; i ++) {
        for (int j = 1; j < n; j ++) {
            for (int x = i; x < n; x ++) {
                for (int y = j; y < n; y ++) {
                    int tmp = getSum(i, j, x, y);
                    if (tmp == 2022)
                        ans = min(ans, (x - i + 1) * (y - j + 1));
                    else if (tmp > 2022)	// 超过 2022 可以剪枝
                        break;
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

题目来源:蓝桥杯-2012省赛-放棋子

题目描述:
在这里插入图片描述

题目思路:

题目代码:

#include <stdio.h>
#include <stdlib.h>
int N = 0;

bool CheckStoneNum(int x[][6])
{
    for(int k=0; k<6; k++)
    {
        int NumRow = 0;
        int NumCol = 0;
        for(int i=0; i<6; i++)
        {
            if(x[k][i]) NumRow++;
            if(x[i][k]) NumCol++;
        }
        if(NumRow!=3||NumCol!=3) return false;  // 填空
    }
    return true;
}

int GetRowStoneNum(int x[][6], int r)
{
    int sum = 0;
    for(int i=0; i<6; i++)     if(x[r][i]) sum++;
    return sum;
}

int GetColStoneNum(int x[][6], int c)
{
    int sum = 0;
    for(int i=0; i<6; i++)     if(x[i][c]) sum++;
    return sum;
}

void show(int x[][6])
{
    for(int i=0; i<6; i++)
    {
        for(int j=0; j<6; j++) printf("%2d", x[i][j]);
        printf("\n");
    }
    printf("\n");
}

void f(int x[][6], int r, int c);

void GoNext(int x[][6],  int r,  int c)
{
    if(c<6)
        f(x,r,c+1);   // 填空
    else
        f(x, r+1, 0);
}

void f(int x[][6], int r, int c)
{
    if(r==6)
    {
        if(CheckStoneNum(x))
        {
            N++;
            show(x);
        }
        return;
    }

    if(x[r][c])  // 已经放有了棋子  // 填空
    {
        GoNext(x,r,c);
        return;
    }
    
    int rr = GetRowStoneNum(x,r);
    int cc = GetColStoneNum(x,c);

    if(cc>=3)  // 本列已满
        GoNext(x,r,c);  
    else if(rr>=3)  // 本行已满
        f(x, r+1, 0);   
    else
    {
        x[r][c] = 1;
        GoNext(x,r,c);
        x[r][c] = 0;
        
        if(!(3-rr >= 6-c || 3-cc >= 6-r))  // 本行或本列严重缺子,则本格不能空着!
            GoNext(x,r,c);  
    }
}

int main(int argc, char* argv[])
{
    int x[6][6] = {
        {1,0,0,0,0,0},
        {0,0,1,0,1,0},
        {0,0,1,1,0,1},
        {0,1,0,0,1,0},
        {0,0,0,1,0,0},
        {1,0,1,0,0,1}
    };

    f(x, 0, 0);
    
    printf("%d\n", N);

    return 0;
}

题目来源:蓝桥杯-2014省赛-兰顿蚂蚁

题目描述:

在这里插入图片描述

题目思路:

题目代码:

#include <iostream>
#include<vector>
using namespace std;
int f[4] = { 0,1,2,3 };
int d[4][2] = { -1,0,0,-1,1,0,0,1 };
int main()
{
    // 请在此输入您的代码
    int m, n;
    cin >> m >> n;
    vector<vector<int>> vec(m, vector<int>(n));
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int a;
            cin >> a;
            vec[i][j] = a;
        }
    }
    int dir = 0;
    int x, y, k;
    string s;
    cin >> x >> y >> s >> k;
    if (s == "U")dir = 0;
    if (s == "L")dir = 1;
    if (s == "D")dir = 2;
    if (s == "R")dir = 3;
    while (k--)
    {
        if (vec[x][y] == 0)
        {
            vec[x][y] = 1;
            dir++;
            if (dir == 4)dir = 0;

        }
        else
        {
            vec[x][y] = 0;
            dir--;
            if (dir == -1)dir = 3;
        }
        x += d[dir][0];
        y += d[dir][1];
    }
    cout << x << " " << y;
    return 0;
}

No.3 图形面积求解

题目来源:蓝桥杯-2012省赛-土地测量

题目描述:
在这里插入图片描述

题目思路:

题目代码:

题目来源:蓝桥杯-2018省赛-方格计数

题目描述:
在这里插入图片描述

题目思路:

题目代码:

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
  long long r=50000,ans=0,pre=0;
  for(long long x=r-1;x>0;x--){
    long long y=sqrt(r*r-x*x);
    ans+=(y-pre)*x*4;
    pre=y;
  }
  cout<<ans;
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值