算法小记

这篇博客记录了作者在刷蓝桥杯题目时遇到的一些算法和数据结构要点,包括:使用`long long`避免整数溢出,递归算法的双向思考,十六进制转八进制的方法,排序函数`sort()`的使用,C++中的`queue`和`stack`操作,以及如何用`vector`实现图的深度优先遍历。此外,还涉及到了动态规划和K好数问题的解决思路。
摘要由CSDN通过智能技术生成

写在前面:

这个是最近刷蓝桥杯的题时感觉需要记录的东西,感觉写在这里方便查阅。

但是自己太懒了OTZ,就想到什么就把他们堆在这里了,等有机会再整理一下吧(就是不会整理了的意思OTZ)

最近更新时间 2018/03/31

正文:

1.用什么int,直接用long long


2.递归算法

    可从前往后考虑,也可从后往前考虑。(经常从后往前考虑简单得多)

3.十六进制转八进制

    先将16进制转为2进制再将2进制转为8进制,1位16进制数对应4位2进制数,1位八进制数对应3位2进制数


4.十进制转十六进制  自己犯的错while(a>0)   没考虑a=0的情况


5.超不了内存的时候,用二维数组要比用两个数组互相赋值简单


6.超级好用的排序函数  sort()   时间复杂度o(nlogn)

需要 头文件#include<algorithm>和using namespace std;

用法  默认从小到大排序 a是数组首地址 a+10就是排序到第10个

int a[20]={2,3,5,1,3,4,8,5,2,1,4};
sort(a,a+10);

自定义类型排序  这里仿照了 https://blog.csdn.net/lu597203933/article/details/41776701 (萌新不知道这么放链接合适吗。。。) 写得很详细

实现对自定义的对象类型进行排序(按照其中的元素),首先将对象存放在vector中,然后利用algorithm库函数中的sort对其进行排序,需要重写排序函数以函数名 
    作为函数指针作为sort的第三个参数 
 
    #include <iostream>  
    #include <string>  
    #include <algorithm>  
    #include <vector>  
    using namespace std;  
      
    struct myclass{  
        int a;  
        int b;  
    };  
    
    void addmyclass(vector<myclass> &vec, int a, int b){  //方便的加入一个自定义类型对象
        myclass m;  
        m.a = a;  
        m.b = b;  
        vec.push_back(m);  
          
}  

    // 按照a排序 升序  
    bool com(const myclass &m1, const myclass &m2){  
        return m1.a < m2.a;  
}  

    // 先按照a排 a一样 按照b排  
    bool comAll(const myclass &m1, const myclass &m2){  
        if(m1.a < m2.a) return true;  
        else if(m1.a > m2.a) return false;  
        else return m1.b < m2.b;  
}  

    int main(){  
        vector<myclass> vec;  
        addmyclass(vec, 20, 1);  
        addmyclass(vec, 20, 2);    

        sort(vec.begin(), vec.end(), comAll);  

        for(vector<myclass>::iterator iter = vec.begin(); iter != vec.end(); ++iter){//vector遍历的好方法
            cout << (*iter).a << " " << (*iter).b << endl;  
        }  
}  

7.C++ 中queue(队列)的用法

#include<queue>      

定义一个queue的变量    queue<Type> q;

查看是否为空范例       q.empty()    是的话返回1,不是返回0;

从已有元素后面增加元素  q.push()

输出现有元素的个数     q.size()

显示第一个元素         q.front()

显示最后一个元素       q.back()

清除第一个元素         q.pop()


8.stack

c++ stl栈stack的头文件为: 

#include <stack> 

c++ stl栈stack的成员函数介绍

操作 比较和分配堆栈

empty() 堆栈为空则返回真

pop() 移除栈顶元素

push() 在栈顶增加元素

size() 返回栈中元素数目

top() 返回栈顶元素


9.利用vector实现图的边链表深度优先遍历  也可以用,即有向图)

 这是一道树形动态规划的题
问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12 
#include <iostream>
#include <vector>
using namespace std;
const int MAX_N = 100005;
int v[MAX_N];//权值
int vis[MAX_N];//记录访问
int n;
vector<int>vec[MAX_N];//存边的信息
//状态转移方程为:dp[s][0]+=dp[u][1];
// dp[s][1]+=max(dp[u][0],dp[u][1]);
//(u为s的子节点,0表示包含自己的以s为根节点的子树最大值
//,1表示不包含自己的以s为根节点的子树最大值)
int dp[MAX_N][2];//状态转移方程用

void dfs(int s) //s代表从s开始向子节点判断
{
    dp[s][0] = v[s];

    for(int i=0; i<vec[s].size(); ++i)
    {
        if(vis[vec[s][i]] == 0)
        {
            vis[vec[s][i]] = 1;
            dfs(vec[s][i]);
            vis[vec[s][i]] = 0;
            //---------------------
            dp[s][0]+=dp[vec[s][i]][1];
            dp[s][1]+=max(dp[vec[s][i]][0],dp[vec[s][i]][1]);
        }
    }
}
void print()//测试用函数
{
    for(int i=1; i<n+1; i++)
    {
        cout<<"i:"<<i<<" "<<dp[i][0]<<" "<<dp[i][1]<<endl;
    }
}
int main()
{
    int a,b;
    cin>>n;
    for(int i=1; i<n+1; i++)
    {
        cin>>v[i];
    }
    for(int i=0; i<n-1; i++) //边
    {
        cin>>a>>b;
        vec[a].push_back(b);
        vec[b].push_back(a);
    }

    vis[1] = 1;
    dfs(1);
    vis[1] = 0;
    //print();
    long long res = max(dp[1][0], dp[1][1]);
    cout<<res;
    return 0;
}

10.答题代码样式参照

#include <iostream>
#include <algorithm>
using namespace std;

const int MAX_N = 1005;
int a[MAX_N];
int t[MAX_N];
int res[MAX_N],ri;
int n,m;
int l,r,k;
//--------------------------
/*
5
1 2 3 4 5
2
1 5 2
2 3 2
*/
//-------------------------
bool com(int a, int b){//从大到小排序
    return a>b;
}
//------------------------
void solve(){
    int i;
    for(i=l; i<=r; i++){
        t[i] = a[i];
    }
    sort(t+l, t+r+1, com);
    res[ri-m-1] = t[l+k];
}
//------------------------
int main()
{
    int i,j;
    cin>>n;
    for(i=0; i<n; i++){
        cin>>a[i];
    }
    cin>>m;
    ri = m;
    while(m--){
        cin>>l>>r>>k;
        l--;r--;k--;//下标从0开始
        solve();
    }
    for(i=0; i<ri; i++)cout<<res[i]<<endl;
    return 0;
}

11.由二维数组来动态规划,由上一状态推下一状态

问题描述

如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数。

求L位K进制数中K好数的数目。例如K = 4,L = 2的时候,所有K好数为11、13、20、22、30、31、33 共7个。

由于这个数目很大,请你输出它对1000000007取模后的值。

输入格式

输入包含两个正整数,K和L。

#include <iostream>
#define MOD %1000000007
using namespace std;
const int MAX_N = 105;
long long a[MAX_N][MAX_N];
int k,l;
long long res;

bool neighbor(int a, int b){//判断a和b是否相邻 相邻为true
    bool flag = false;
    if(a-1 == b)flag = true;
    if(b-1 == a)flag = true;
    return flag;
}

void print(){//测试函数
    int i,j;
    cout<<endl<<"a:"<<endl;
    for(i=0; i<l; i++){
        for(j=0; j<k; j++){
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main()
{
    int i,j,h;
    cin>>k>>l;
    a[0][0] = 0;//开头不能为0
    for(i=1; i<k; i++){
        a[0][i] = 1;//其他数字都可以用
    }

    for(i=1; i<l; i++){//每一位
        for(j=0; j<k; j++){//每个数
            for(h=0; h<k; h++){//由上一位的每个数来计算
                if(!neighbor(j,h))a[i][j] = (a[i][j] + a[i-1][h]) MOD;//由上一状态推下一状态
            }
        }
    }

    for(i=0; i<k; i++){
        res = (res + a[l-1][i]) MOD;
    }
    cout<<res;
    return 0;
}

12.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值