蓝桥杯考前冲刺--->最后的算法文章--->剩下时间好好复习吧

蓝桥杯考前冲刺

一,奇技淫巧

1.手写:1.迷宫 - 蓝桥云课 (lanqiao.cn)

直接画图

image

2.word查找:1.门牌制作 - 蓝桥云课 (lanqiao.cn)

3.处理日期:1.星期一 - 蓝桥云课 (lanqiao.cn)

excel:

image

python:

image

from datetime import *
dt1=datetime(1901,1,1)
dt2=datetime(2000,12,31)
print(dt1.weekday())
1
td=dt2-dt1
print(td)
36524 days, 0:00:00
print(td//7)
5217 days, 17:08:34.285714
print(td.days//7)
5217

4.大数处理:1.乘积尾零 - 蓝桥云课 (lanqiao.cn)

import os
import sys

data="5650 4542 3554 473 946 4114 3871 9073 90 4329 \
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594 \
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899 \
1486 5722 3135 1170 4014 5510 5120 729 2880 9019 \
2049 698 4582 4346 4427 646 9742 7340 1230 7683 \
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649 \
6701 6645 1671 5978 2704 9926 295 3125 3878 6785 \
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915 \
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074 \
689 5510 8243 6114 337 4096 8199 7313 3685 211 "
num=data.split()
s=1
for i in num:
  s=s*int(i)
cnt=0
while s%10==0:
  s//=10
  cnt+=1;
print(cnt)

5.字符串处理:1.平方和 - 蓝桥云课 (lanqiao.cn)

sum=0
for i in range(1,2019+1):
  s=str(i)
  if '0' in s or '2' in s or '1' in s or '9' in s:
    sum+=i*i
print(sum)

6.手算找规律:1.切面条 - 蓝桥云课 (lanqiao.cn)

image

#include<bits/stdc++.h>
using namespace std;
int main()
{
  cout<<pow(2,10)+1<<endl;

  return 0;
}

7.付账问题贪心:1.付账问题 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
const int N=500005;
int a[N];
int main()
{
  int n;int sum_;cin>>n;cin>>sum_; 
  for(int i=0;i<n;i++)
  {
    cin>>a[i];
  }
  sort(a,a+n);
  double avg=1.0*sum_/n;  //转化成小数
  double ssum=0;
  //进行分类一个是钱数<=avg的,另一个是钱的数量>avg的,需要全部拿出来
  //现在我们的数据具有性质了
  for(int i=0;i<n;i++)
  {
    if(a[i]*(n-i)<sum_)  //这里是因为总数是n个吧,然后第一次变为了 a[i]*n<sum_的情况   第二次sum_发生了更新此时sum_已经减去了a[0]的数据所以这里自然是a[i]*(n-1)<新sum_
    {
      ssum+=(a[i]-avg)*(a[i]-avg);
      sum_-=a[i];
    }
    else//此时已经全部够了
    { 
      double cur_avg=1.0*sum_/(n-i);
      ssum+=(avg-cur_avg)*(avg-cur_avg)*(n-i);
      break;
    }
  }
  printf("%.4lf",sqrt(ssum/n));
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N=500005;
long long a[N];
int main()
{
  int n;long long sum_;cin>>n;cin>>sum_; 
  for(int i=0;i<n;i++)
  {
    cin>>a[i];
  }
  sort(a,a+n);
  double avg=1.0*sum_/n;  //转化成小数
  double ssum=0;
  //进行分类一个是钱数<=avg的,另一个是钱的数量>avg的,需要全部拿出来
  //现在我们的数据具有性质了
  for(int i=0;i<n;i++)
  {
    if(a[i]*(n-i)<sum_)  //这里是因为总数是n个吧,然后第一次变为了 a[i]*n<sum_的情况   第二次sum_发生了更新此时sum_已经减去了a[0]的数据所以这里自然是a[i]*(n-1)<新sum_
    {
      ssum+=(a[i]-avg)*(a[i]-avg);
      sum_-=a[i];
    }
    else//此时已经全部够了
    { 
      double cur_avg=1.0*sum_/(n-i);
      ssum+=(avg-cur_avg)*(avg-cur_avg)*(n-i);
      break;
    }
  }
  printf("%.4lf",sqrt(ssum/n));
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N=500005;
int a[N];
int main()
{
  int n;long long sum_;cin>>n;cin>>sum_; 
  for(int i=0;i<n;i++)
  {
    cin>>a[i];
  }
  sort(a,a+n);
  double avg=1.0*sum_/n;  //转化成小数
  double ssum=0;
  //进行分类一个是钱数<=avg的,另一个是钱的数量>avg的,需要全部拿出来
  //现在我们的数据具有性质了
  for(int i=0;i<n;i++)
  {
    if((long long)a[i]*(n-i)<sum_)  //这里是因为总数是n个吧,然后第一次变为了 a[i]*n<sum_的情况   第二次sum_发生了更新此时sum_已经减去了a[0]的数据所以这里自然是a[i]*(n-1)<新sum_
    {
      ssum+=(a[i]-avg)*(a[i]-avg);
      sum_-=a[i];
    }
    else//此时已经全部够了
    { 
      double cur_avg=1.0*sum_/(n-i);
      ssum+=(avg-cur_avg)*(avg-cur_avg)*(n-i);
      break;
    }
  }
  printf("%.4lf",sqrt(ssum/n));
  return 0;
}

这里int范围虽然没有爆int但是出现一个问题:a[i]*(n-i)如果不发生强制类型转换的话会爆出int

8.普通:1.纸张尺寸 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int main()
{
  int long_=1189,short_=841;
  char a;int b;
  cin>>a>>b;
  while(b--)
  {
    long_ /=2;
    if(short_>long_)
      swap(short_,long_);
  } 
  cout<<long_<<endl<<short_<<endl;
  return 0;
}

9.普通:1.排列字母 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int main()
{
  string str="WHERETHEREISAWILLTHEREISAWAY";
  sort(str.begin(),str.end());
  cout<<str<<endl;
  return 0;
}

10,调试技巧

Dev-c++ 2:解决无法调试 & 调试步骤_dev c++ 不能调试的解决 法-CSDN博客

蓝桥杯竞赛小白必学!开发环境:devC++调试方法_devc++蓝桥杯-CSDN博客

二,工具函数

1.vector容器

#include <vector>   //头文件
vector<int> a;      //定义了一个int类型的vector容器a
vector<int> b[100]; //定义了一个int类型的vector容器b组
struct rec
{
    ···
};
vector<rec> c;            //定义了一个rec类型的vector容器c
vector<int>::iterator it; //vector的迭代器,与指针类似

a.size()           //返回实际长度(元素个数),O(1)复杂度
a.empty()      //容器为空返回1,否则返回0,O(1)复杂度
a.clear()      //把vector清空
a.begin()      //返回指向第一个元素的迭代器,*a.begin()与a[0]作用相同
a.end()        //越界访问,指向vector尾部,指向第n个元素再往后的边界
a.front()      //返回第一个元素的值,等价于*a.begin和a[0]
a.back()       //返回最后一个元素的值,等价于*--a.end()和a[size()-1]
a.push_back(x) //把元素x插入vector尾部
a.pop_back()   //删除vector中最后一个元素

 for ( vector<int>::iterator it=a.begin() ; it!=a.end() ; it++ )
 cout<<*it<<endl;
 for ( auto it=a.begin() ; it!=a.end() ; it++ )
 cout<<*it<<endl;
//法一


for( int i=0;i<a.size();i++) cout<<a[i]<<endl;
//法二

2.queue容器

queue<string> myqueue;
queue<int> myqueue_int;

image

3.map容器

image

map<char, int> mymap1;
map<string, int> mymap2;

//1.看容量
int map.size();//查询map中有多少对元素
bool empty();// 查询map是否为空

//2.插入
map.insert(make_pair(key,value));
//或者
map.insert(pair<char, int>(key, value))
//或者
map[key]=value

//3.取值
map<int, string> map;

//如果map中没有关键字2233,使用[]取值会导致插入
//因此,下面语句不会报错,但会使得输出结果结果为空
cout<<map[2233]<<endl;

//但是使用使用at会进行关键字检查,因此下面语句会报错
map.at(2016) = "Bob";


//4.遍历
map<string, string>::iterator it;
for (it = mapSet.begin(); it != mapSet.end(); ++it)
{
    cout << "key" << it->first << endl;

    cout << "value" << it->second << endl;
}

//5.查找
m.count(key)://由于map不包含重复的key,因此m.count(key)取值为0,或者1,表示是否包含。
m.find(key)://返回迭代器,判断是否存在。

unordered_map不排序,内部实现为哈希

4.set容器

image

#include <bits/stdc++.h>
using namespace std;



// 1.set 的定义 set<数据类型> 变量名

set<int> intSet;
set<string> stringSet;

int main()
{
    string s1="测试1";
    string s2="测试2";
    string s3="测试3";

    //2. 插入操作
    stringSet.insert(s3);
    stringSet.insert(s1);

    //5. 返回集合元素数量
    printf("前2次插入操作完成后的元素数量为%d\n",stringSet.size());
    stringSet.insert(s2);
    printf("前3次插入操作完成后的元素数量为%d\n",stringSet.size());

    //6.遍历整个集合,借助迭代器实现
    //定义方式   容器类型< type> ::iterator name
    set<string> ::iterator  setStringIterator;
    for(setStringIterator=stringSet.begin();setStringIterator!=stringSet.end();setStringIterator++)
        cout<<*setStringIterator<<" ";
    puts("");

    //3. 删除操作
    stringSet.erase(s3);
    printf("删除操作完成后的元素数量为%d\n",stringSet.size());

    for(setStringIterator=stringSet.begin();setStringIterator!=stringSet.end();setStringIterator++)
        cout<<*setStringIterator<<" ";
    puts("");

    //4. 判断是否由此元素
    if(stringSet.count(s2)!=0) cout<<"存在元素"<<s2<<endl;
}

5.stack容器

6.比较函数

image

7.使用队列:1.CLZ银行问题 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
queue<string> qv;
queue<string> qn;
int main()
{
  int m;cin>>m;
  while(m--)
  {
    string op;cin>>op;
    if(op=="IN")
    {
      string name,ch;
      cin>>name>>ch;
      if(ch=="V")
      {
        qv.push(name);
      }
      else
      {
        qn.push(name);
      }
    }
    else if(op=="OUT")
    {
      string ch;
      cin>>ch;
      if(ch=="V")
      {
        qv.pop();
      }
      else
      {
        qn.pop();
      }
    }
  }
  while(qv.size())
  {
    cout<<qv.front()<<endl;
    qv.pop();
  }
  while(qn.size())
  {
    cout<<qn.front()<<endl;
    qn.pop();
  }
  return 0;
}

8.使用set:

#include<bits/stdc++.h>
using namespace std;
set<string> ap;
int main()
{
  int n;cin>>n;int flag=1;
  while(n--)
  {
    string a;cin>>a;
    if(ap.count(a))
    {
      cout<<a<<endl;
      flag=0;
    }
    ap.insert(a);
  }
  if(flag)
  {
    cout<<"NO"<<endl;
  }
  return 0;
}

6
1fagas 
dsafa32j
lkiuopybncv
hfgdjytr
cncxfg
sdhrest

9.使用map:1.快递分拣 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;
map<string, vector<string>>mp;//分别放城市和单号
vector<string> citys;//用于存储出现过的城市名
int main()
{
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++)//循环读取单号和城市
    {
        string d, c;//单号,城市
        cin >> d>> c;
        if (!mp.count(c))//也可以写成 if(mp.find(c) == mp.end())--说明没有找到
        {
            citys.push_back(c);//如果这个城市之前没出现过就把他放在citys中
        }
        mp[c].push_back(d);//无论城市是否已经出现过都要讲单号添加到mp城市的后面
    }//以上两步的顺序如果颠倒,那么if语句将始终无法运行
    for (const auto& city : citys)//遍历citys中的每一个城市名
    {
        cout << city << ' ' << mp[city].size() << endl;//后者是mp中的键【city】后所对应的【值】的大小,即有几个单号
        for (const auto& i : mp[city])//遍历每一个值--单号
        {
            cout << i << endl;
        }
    }
    return 0;
}

三,枚举与双指针法

1.暴力枚举:第几个幸运数字 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int main()
{
    long long a=59084709587505;
    int cnt=0;
    for(int i=0;pow(3,i)<a;i++)
    {
        for(int j=0;pow(5,j)<a;j++)
        {
            for(int k=0;pow(7,k)<a;k++)
            {
                if(pow(3,i)*pow(5,j)*pow(7,k)<=a) cnt++;
            }
        }
    }
    cout<<cnt-1<<endl;
    return 0;
}

2.组合型枚举93. 递归实现组合型枚举 - AcWing题库

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=30;//way[u]其中u最大为30,u是代表第几个数
int n,m;//从n中选择m个数
int way[N];

void dfs(int u,int start)
{
    //额外补充:剪纸操作,例如当 4 占据第一个位置的时候实际上已经可以不用进行操作了
    //公式:1.已经使用了u-1个数 距离n也就是数的上限还差 n-start+1
    //      2.u-1+n-start+1<m 的时候就应该进行剪枝操作了
    if(u+n-start<m) return;
    if(u-1==m)//u-1代表已经选取了u-1个数恰好等于m的时候,就可以返回结果了
    {
        for(int i=1;i<=m;i++)
        {
            cout<<way[i]<<" ";
        }
        cout<<endl;
    }
    //进行递归操作
    for(int i=start;i<=n;i++)
    {
        way[u]=i;
        dfs(u+1,i+1);//下一个要使用的u就是u+1;start从i+1开始
        way[u]=0;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    dfs(1,1);//第二个也就是start记录了开始的数字
    return 0;
}

//cnm
#include<bits/stdc++.h>
using namespace std;
vector<int> chosen;
int n,m;
void dfs(int u,int start)//第一个数代表当前处理的数
{
    if(chosen.size()>m) return;//剪枝操作1
    if(u+n-start<m) return;
    if(u-1==m)
    {
        for(auto&p:chosen)
        {
            cout<<p<<" ";
        }
        cout<<endl;
    }
    for(int i=start;i<=n;i++)
    {
        chosen.push_back(i);
        dfs(u+1,i+1);
        chosen.pop_back();
    }
}
int main()
{
    
    cin>>n>>m;
    dfs(1,1);//代表第一个位置放数,第二个位置是开始的数;
    return 0;
}

//cnm vector精简版
#include<bits/stdc++.h>
using namespace std;
vector<int> chosen;
int n,m;
void dfs(int start)//
{
    if(chosen.size()>m) return;//剪枝操作1
    if(chosen.size()+(n-start+1)<m) return;
    if(chosen.size()==m)
    {
        for(auto&p:chosen)
        {
            cout<<p<<" ";
        }
        cout<<endl;
    }
    for(int i=start;i<=n;i++)
    {
        chosen.push_back(i);
        dfs(i+1);
        chosen.pop_back();
    }
}
int main()
{
    
    cin>>n>>m;
    dfs(1);//代表第一个位置放数,第二个位置是开始的数;
    return 0;
}

3.排列形枚举94. 递归实现排列型枚举 - AcWing

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=9;
int n;
int st[N];//st代表状态,0表示还没有放数,1->n代表放了什么数
bool used[N];//true表示用过,false表示没用过
void dfs(int u)
{
    if(u>n)
    {
        for(int i=1;i<=n;i++)
        {
            printf("%d ",st[i]);
        }
        puts("");
    }
    // 依次枚举每个数,即当前位置可以填哪些数
    for(int i=1;i<=n;i++)
    {
        if(!used[i])
        {
            st[u]=i;
            used[i]=true;

            dfs(u+1);

            st[u]=0;
            used[i]=false;
        }
    }
}

int main()
{
    cin>>n;
    dfs(1);
    return 0;
}

4.指数型枚举:dfs+二进制方法92. 递归实现指数型枚举 - AcWing题库

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=9;
int n;
int st[N];//st代表状态,1是说选中了,0是未选中状态,2是归位状态
void dfs(int u)
{
    if (u > n)
    {
        for (int i = 1; i <= n; i ++ )
            if (st[i] == 1)
            {
                printf("%d ", i);
            }
        puts("");
        return;
    }
    
    st[u]=0;//不选的状态
    dfs(u+1);
    st[u]=2;//回复现场
    
    st[u]=1;//选的状态
    dfs(u+1);
    st[u]=2;//回复现场
}

int main()
{
    cin>>n;
    dfs(1);
    return 0;
}

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
int a[20];
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        a[i]=i+1;
    }
    for(int i=0;i<(1<<n);i++)//遍历位置的每个不同的情况
    {
        for(int j=0;j<n;j++)//一次情况的每一个位置
        {
            if(i&(1<<j))
            {
                cout<<a[j]<<" ";
            }
        }
        cout<<endl;
    }
    
    return 0;
}

5.C++排列型枚举特殊方法:next_permutation:排列序数 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;cin>>n;
    string a="abc";
    do{
        cout<<a<<endl;
    }while(next_permutation(a.begin(),a.end()));
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string a;cin>>a;
    string olds;olds=a;
    int cnt=0;
    sort(a.begin(),a.end());
    do{
        if(olds==a)
        {
            cout<<cnt<<endl;
            break;
        }
        cnt++;
    }while(next_permutation(a.begin(),a.end()));
    return 0;
}

6.排列型枚举:火星人 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int a[10011];
int main()
{
  int n,m;cin>>n>>m;
  for(int i=1;i<=n;i++) cin>>a[i];
  for(int i=1;i<=m;i++) next_permutation(a+1,a+n+1);
  for(int i=1;i<=n;i++) cout<<a[i]<<" ";
  return 0;
}

7,排列枚举:座次问题 - 蓝桥云课 (lanqiao.cn)

//排列dfs
#include<bits/stdc++.h>
using namespace std;
string a[13];
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    do{
        for(int i=0;i<n;i++)
        {
            cout<<a[i]<<" ";
        }
        cout<<endl;
    }while(next_permutation(a,a+n));
    return 0;
}

//排列dfs
#include<bits/stdc++.h>
using namespace std;
string a[13];
string oou[13];
bool used[13];
int n;
void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
        {
            cout<<oou[i]<<" ";
        }
        cout<<endl;
    }
    for(int i=0;i<n;i++)
    {
        if(!used[i])
        {
            oou[u]=a[i];
            used[i]=true;

            dfs(u+1);

            oou[u]="0";
            used[i]=false;
            
        }
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    dfs(0);//第一个位置是枚举数的个数,第二个数是枚举开始的数据a[0];
    return 0;
}

8.组合枚举:公平抽签 - 蓝桥云课 (lanqiao.cn)

//组合型枚举
#include <iostream>
using namespace std;
int n,m;
string a[17];
string oou[17];
void dfs(int u,int start)
{
    if(u==m)
    {
        for(int i=0;i<m;i++)
        {
            cout<<oou[i]<<" ";
        }
        cout<<endl;
    }
    for(int i=start;i<n;i++)
    {
        oou[u]=a[i];
        dfs(u+1,i+1);
        oou[u]="0";
    }
}
int main()
{
    cin>>n>>m;//从n中选m个    
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    dfs(0,0);
    return 0;
}

9.双指针:回文判定 - 蓝桥云课 (lanqiao.cn)

#include <iostream>
using namespace std;
int main()
{
    string a;cin>>a;
    int sizee=a.size();
    for(int i=0,j=sizee-1;i<j;i++,j--)
    {
        if(a[i]!=a[j])
        {
            cout<<"N"<<endl;
            return 0;
        }
    }
    cout<<"Y"<<endl;
    return 0;
}

#include <iostream>
using namespace std;
int main()
{
    string a;cin>>a;
    int sizee=a.size();
    int flag=1;
    for(int i=0,j=sizee-1;i<j;i++,j--)
    {
        if(a[i]!=a[j])
        {
            flag=0;
            cout<<"N"<<endl;
        }
    }
    if(flag) cout<<"Y"<<endl;
    return 0;
}

10.双指针:互补的整数对 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int a[100010];
int main()
{
    int n,s;cin>>n>>s;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n);
    int res=0;
    int i=0,j=n-1;
    while(i<j)
    {
        int sum=a[i]+a[j];
        if(sum>s)
        {
            j--;
        }
        else if(sum<s)
        {
            i++;
        }
        else
        {
            res++;
            i++,j--;
        }a
    }
    cout<<res<<endl;
    return 0;
}

11.双指针:1.美丽的区间 - 蓝桥云课 (lanqiao.cn)

#include <iostream>
using namespace std;
int a[100040],sum[100040];
int main()
{
    int n,s;cin>>n>>s;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]+=sum[i-1]+a[i];
    }
    int res=0x7f7f7f7f;
    int flag=0;
    for(int i=1,j=1;j<=n;)
    {
        if(sum[j]-sum[i-1]<s)
        {
            j++;
        }
        if(sum[j]-sum[i-1]>=s)
        {
            flag=1;
            res=min(res,j-i+1);
            i++;
        }
    }
    if(flag==0) cout<<0<<endl;
    else cout<<res<<endl;
    return 0;
}

四,递归与递推

1.斐波那契数列的递归与递推和记忆化

递推表达式:f(n)=f(n-1)+f(n-2)

int fib[25];
int main()
{
	fib[1] = fib[2] = 1;
	for (int i = 3; i <= 20; i++)
	{
		fib[i] = fib[i - 1] + fib[i - 2];
	}
	cout << fib[20] << endl;
	return 0;
}

递归:

int cnt = 0;
int dfs_fib(int n)
{
	cnt++;
	if (n == 1 || n == 2) return 1;
	else return dfs_fib(n - 1) + dfs_fib(n - 2);
}
int main()
{
	cout << dfs_fib(20) << endl;//6765
	cout <<"递归进行了几次:" << cnt;//递归进行了几次:13529
	return 0;
}

记忆化递归:减少递归的次数

int cnt = 0;
int dat[25];
int dfs_fib(int n)
{
	cnt++;
	if (dat[n] != 0) return dat[n];
	if (n == 1 || n == 2) return 1;
	dat[n]=dfs_fib(n - 1) + dfs_fib(n - 2);
	return dat[n];
}
int main()
{
	cout << dfs_fib(20) << endl;//6765
	cout <<"递归进行了几次:" << cnt;//递归进行了几次:37
	return 0;
}

2.递推:数字三角形:数字三角形 - 蓝桥云课 (lanqiao.cn)

image

#include<bits/stdc++.h>
using namespace std;
int n;//有多少层
int  a[111][111];//每行每列有多少
int main()
{
    //输入数据
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            cin>>a[i][j];
        }
    }
    //从下向上的向下选择
    for(int i=n-1;i>=1;i--)
    {
        for(int j=1;j<=i;j++)
        {
            if(a[i+1][j]<a[i+1][j+1])
                a[i][j]+=a[i+1][j+1];
            else 
                a[i][j]+=a[i+1][j];
        }
    }
    cout<<a[1][1]<<endl;

    return 0;
}

3.42点问题:42点问题 - 蓝桥云课 (lanqiao.cn)

image

image

//借助vector<>容器的做法
 #include<bits/stdc++.h>
using namespace std;
int a[6];
int main()
{
    //数据的输入
    for(int i=0;i<6;i++)
    {
        char c;cin>>c;
        if(c=='A')
        {
            a[i]=1;
        }
        else if(c=='K')
        {
            a[i]=13;
        }
        else if(c=='Q')
        {
            a[i]=12;
        }
        else if(c=='J')
        {
            a[i]=11;
        }
        else
        {
            a[i]=c-'0';
        }
    }
    //数据的处理
    vector<int> ans[6];
    ans[0].push_back(a[0]);
    for(int i=1;i<=5;i++)
    {
        for(int j=0;j<ans[i-1].size();j++)
        {
            ans[i].push_back(a[i-1][j]+a[i]);
            ans[i].push_back(a[i-1][j]-a[i]);
            ans[i].push_back(a[i-1][j]*a[i]);
            ans[i].push_back(int(a[i-1][j]/a[i]));
        }
    }
    int flag=0;
    for(int i=0;i<ans[5].size();i++)
    {
        if(a[5][i]==42)
        {
            flag=1;
        }
    }
    if(flag) cout<<"YES"<<endl;
    esle cout<<"NO"<<endl;
    return 0;
 }

错误:ans和a混乱

//借助vector<>容器的做法
 #include<bits/stdc++.h>
using namespace std;
int a[6];
int main()
{
    //数据的输入
    for(int i=0;i<6;i++)
    {
        char c;cin>>c;
        if(c=='A')
        {
            a[i]=1;
        }
        else if(c=='K')
        {
            a[i]=13;
        }
        else if(c=='Q')
        {
            a[i]=12;
        }
        else if(c=='J')
        {
            a[i]=11;
        }
        else
        {
            a[i]=c-'0';
        }
    }
    //数据的处理
    vector<int> ans[6];
    ans[0].push_back(a[0]);
    for(int i=1;i<=5;i++)
    {
        for(int j=0;j<int(ans[i-1].size());j++)
        {
            ans[i].push_back(ans[i-1][j]+a[i]);
            ans[i].push_back(ans[i-1][j]-a[i]);
            ans[i].push_back(ans[i-1][j]*a[i]);
            ans[i].push_back(int(ans[i-1][j]/a[i]));
        }
    }
    int flag=0;
    for(int i=0;i<int(ans[5].size());i++)
    {
        if(ans[5][i]==42)
        {
            flag=1;
        }
    }
    if(flag) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return 0;
 }

//dfs
#include<bits/stdc++.h>
using namespace std;
int a[6];
int flag = 0;
char opt[6];
char all[4] = { '+','-','*','/' };
//运算函数
int calculate(int num1, int num2, char op)
{
    switch (op)
    {
    case '+':
        return num1 + num2;
    case '-':
        return num1 - num2;
    case '*':
        return num1 * num2;
    case '/':
        return num1 / num2;
    }
}
void dfs(int u)
{
    if (u == 5)
    {
        if (42 == calculate(calculate(calculate(calculate(calculate(a[0], a[1], opt[0]), a[2], opt[1]), a[3], opt[2]), a[4], opt[3]), a[5], opt[4]))
        {
            flag = 1;
            return;
        }
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        opt[u] = all[i];
        dfs(u + 1);
        opt[u] = '%';//回复现场
    }
}
int main()
{
    //数据的输入
    for (int i = 0; i < 6; i++)
    {
        char c; cin >> c;
        if (c == 'A')
        {
            a[i] = 1;
        }
        else if (c == 'K')
        {
            a[i] = 13;
        }
        else if (c == 'Q')
        {
            a[i] = 12;
        }
        else if (c == 'J')
        {
            a[i] = 11;
        }
        else
        {
            a[i] = c - '0';
        }
    }
    dfs(0);//代表第0个位置
    if (flag) cout << "YES" << endl;
    if (!flag) cout << "NO" << endl;
    return 0;
}

4.模拟递归递推:数的计算:数的计算 - 蓝桥云课 (lanqiao.cn)

image

#include<bits/stdc++.h>
using namespace std;
int f[10010];
int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i/2;j++)
        {
            f[i]+=f[j];
        }
        f[i]+=1;
    }
    cout<<f[n]<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
int res=1;
void dfs(int n)
{
    if(n==1) return ;
    for(int i=1;i<=n/2;i++)
    {
        res++;
        dfs(i);
    }
}
int main()
{
    int n;cin>>n;
    dfs(n);
    cout<<res<<endl;
    return 0;
}

5.数字dp递推:数的划分:数的划分 - 蓝桥云课 (lanqiao.cn)

image

#include<bits/stdc++.h>
using namespace std;
int shuweidp[202][8];
int main()
{
    int n,k;cin>>n>>k;
    shuweidp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=k;j++)
        {
            if(i>=j) shuweidp[i][j]=shuweidp[i-j][j]+shuweidp[i-1][j-1];
        }
    }
    cout<<shuweidp[n][k]<<endl;
    return 0;
}

6.简单:天干地支:天干地支 - 蓝桥云课 (lanqiao.cn)

#include <iostream>
using namespace std;
string tiangan[10]={"jia","yi","bing","ding","wu","ji","geng","xin","ren","gui"};
string dizhi[12]={"zi","chou","yin","mao","chen","si","wu","wei","shen","you","xu","hai"};
int main()
{
  //天干10年一轮,地支12一轮
  int n;cin>>n;
  cout<<tiangan[(n%10+6)%10]<<dizhi[(n%12+8)%12]<<endl;
  return 0;
}

五,搜索算法

0.dfs和bfs的基本范式

int check(参数)
{
  
}
bool pd(参数)
{
    
}
void dfs(int step)
{
        判断check()
        {
            不在边界内,即回溯
        }
        尝试每一种可能
        {
               满足pd条件

               标记

               继续下一步dfs(step+1)

               恢复初始状态(回溯的时候要用到)
        }
}

int check(参数)
{
    if(满足条件)
        return 1;
    return 0;
}
bool pd(参数){
    相应操作
}
void bfs()
{
    1. 把根节点放入队列尾端
    2. 每次从队列中取出一个节点
    3. Check 判断是不是答案,如果是结束算法 return;
    4. 把当前取出的节点扩展,如果扩展后的节点经Pd()后符合要求,就放入队列,不符合就不放。
    5. 转到步骤2,循环执行
}

如果所有节点被扩展完了,没有找到答案就无解。

bfs解题流程:
1. 初始状态入队
2. while(队列不是空的)
2.1 取出队头元素放入t,并弹出队头
2.2 for(扩展队列) 经过判重,将新节点插入队尾

1.dfs:1.N皇后问题 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int x[15]={0};//这个用来表示列不用关系行,因为我们处理时将每行都处理出来了
int n,ans;
int pd(int a)
{
    for(int i=1;i<a;i++)
    {
        //在对角线上
        if(abs(a-i)==abs(x[a]-x[i]))
        {
            return 0;
        }
        //在同一列上
        else if(x[i]==x[a])
        {
            return 0;
        }
    }
    return 1;
}
void dfs(int a)
{
    //1.判断边界情况也就是超出的情况
    if(a>n)
    {
        ans++;
        return;
    }
    //2.尝试每一种可能
    for(int i=1;i<=n;i++)
    {
        x[a]=i;//第a个n皇后放的列数
        if(pd(a))//判断这一步能否成立
        {
            dfs(a+1);//可以的话就放置下一个皇后
        }
        else
            continue;//不可以的话跳到下一个循环
    }
}
int main()
{
    cin>>n;
    dfs(1);//放置第一个n皇后
    cout<<ans<<endl;
    return 0;
}

2.dfs:1.路径之谜 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int row[25],column[25];
bool flag[25][25];
int n;
typedef pair<int,int> PII;
vector<PII> res;
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
bool check(int x,int y)
{
    if(x==n && y==n)
    {
        for(int i=1;i<=n;i++)
        {
            if(column[i]!=0) return false;
            if(row[i]!=0)   return false;
        }
        return true;
    }
    else return false;
}
bool pd(int x,int y)//看看是否加入
{
    if(flag[x][y]==1 || x<1 || x>n || y<1 ||y>n ||column[x]<=0 ||row[y]<=0) return 0;
    else return 1; 
}
void dfs(int x,int y)
{
    if(check(x,y))//判断是否结束
    {
        for(int i=0;i<res.size();i++)
        {
            int x1=res[i].first;
            int y1=res[i].second;
            int sum=n*(x1-1)+y1-1;
            cout<<sum<<" ";
        }
        cout<<endl;
        return;
    }
    else
    {
        for(int i=0;i<4;i++)
        {
            int xt=dx[i]+x;
            int yt=dy[i]+y;
            if(!pd(xt,yt))  continue;//判断不成立,遍历下一个i
            else
            {
                flag[xt][yt]=true;

                column[xt]--;
                row[yt]--;
                res.push_back({xt,yt});

                //回复现场
                res.pop_back();
                flag[xt][yt]=false;
                column[xt]++;
                row[yt]++;
            }
        }
    }
}
int main()
{
    cin>>n;//表示n*n
    for(int i=1;i<=n;i++)
    {
        cin>>row[i];
    }
    for(int j=1;j<=n;j++)
    {
        cin>>column[j];
    }
    row[1]--;
    column[1]--;
    res.push_back({1,1});
    dfs(1,1);
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
int row[30],column[30];
bool flag[30][30];
int n;
typedef pair<int,int> PII;
vector<PII> res;
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
bool check(int x,int y)
{
    if(x==n && y==n)
    {
        for(int i=1;i<=n;i++)
        {
            if(column[i]!=0) return false;
            if(row[i]!=0)   return false;
        }
        return true;
    }
    else return false;
}
bool pd(int x,int y)//看看是否加入
{
    if(flag[x][y]==1 || x<1 || x>n || y<1 ||y>n ||column[x]<=0 ||row[y]<=0) return 0;
    else return 1; 
}
void dfs(int x,int y)
{
    if(check(x,y))//判断是否结束
    {
        for(int i=0;i<res.size();i++)
        {
            int x1=res[i].first;
            int y1=res[i].second;
            int sum=n*(x1-1)+y1-1;
            cout<<sum<<" ";
        }
        cout<<endl;
        return;
    }
    else
    {
        for(int i=0;i<4;i++)
        {
            int xt=dx[i]+x;
            int yt=dy[i]+y;
            if(!pd(xt,yt))  continue;//判断不成立,遍历下一个i
            else
            {
                flag[xt][yt]=true;

                column[xt]--;
                row[yt]--;
                res.push_back({xt,yt});
                dfs(xt,yt);
                //回复现场
                res.pop_back();
                flag[xt][yt]=false;
                column[xt]++;
                row[yt]++;
            }
        }
    }
}
int main()
{
    cin>>n;//表示n*n
    for(int i=1;i<=n;i++)
    {
        cin>>row[i];
    }
    for(int j=1;j<=n;j++)
    {
        cin>>column[j];
    }
    flag[1][1]=true;
    row[1]--;
    column[1]--;
    res.push_back({1,1});
    dfs(1,1);
    return 0;
}

3.bfs:1.长草 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
const int N=1050;
char aa[N][N];
int n,m,k;
typedef pair<int,int> PII;
queue<PII> q;
int cnt=0;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int len;
void bfs()
{
    //1. 初始状态入队
    //2. while(队列不是空的)
    while(q.size()&&k>0)
    {
        //2.1 取出队头元素放入t,并弹出队头
        PII t=q.front();
        q.pop();
        len--;
        //2.2 for(扩展队列) 经过判重,将新节点插入队尾
        for(int i=0;i<4;i++)
        {
            int a=t.first+dx[i],b=t.second+dy[i];
            if(a<=0||a>m||b<=0||b>n||aa[a][b]=='g') continue;
            aa[a][b]='g';
            q.push({a,b});
        }
        if(len==0)
        {
            k--;
            len=q.size();
        }
    }
}
int main()
{
    //数据输入
    cin>>m>>n;
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>aa[i][j];
            if(aa[i][j]=='g')    q.push({i,j});
        }
    }
    cin>>k;
    //数据处理
    len=q.size();//记录k=0时有多少个节点
    bfs();
    //输出
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<aa[i][j];
        }
        cout<<endl;
    }
    return 0;
}

4.bfs:1.走迷宫 - 蓝桥云课 (lanqiao.cn)献给阿尔吉侬的花束

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
queue<PII> q;
int n,m;
PII start,endd;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int maap[110][111];
int dist[110][111];
bool used[110][111];//不可以往回走
int bfs(PII start,PII endd)
{
    q.push(start);
    dist[1][1]=0;
    used[1][1]=true;
    while(q.size())
    {
        PII t=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int a=t.first+dx[i],b=t.second+dy[i];
            if(a<1||a>n||b<1||b>m||maap[a][b]==0||used[a][b]) continue;
            q.push({a,b});
            dist[a][b]=1+dist[t.first][t.second];
            used[a][b]=true;
            if(a==endd.first&&b==endd.second)
            {
                return dist[a][b];
            }
        }
    }
    return -1;

}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>maap[i][j];
        }
    }
    int x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;
    start={x1,y1},endd={x2,y2};
    int distance=bfs(start,endd);
    if(distance!=-1) cout<<distance<<endl;
    else cout<<"-1"<<endl;
    return 0;
}

5.bfs:1.迷宫 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;

string maze[30]= {//30行 0->29   50列 0->49
                  "01010101001011001001010110010110100100001000101010",
                  "00001000100000101010010000100000001001100110100101",
                  "01111011010010001000001101001011100011000000010000",
                  "01000000001010100011010000101000001010101011001011",
                  "00011111000000101000010010100010100000101100000000",
                  "11001000110101000010101100011010011010101011110111",
                  "00011011010101001001001010000001000101001110000000",
                  "10100000101000100110101010111110011000010000111010",
                  "00111000001010100001100010000001000101001100001001",
                  "11000110100001110010001001010101010101010001101000",
                  "00010000100100000101001010101110100010101010000101",
                  "11100100101001001000010000010101010100100100010100",
                  "00000010000000101011001111010001100000101010100011",
                  "10101010011100001000011000010110011110110100001000",
                  "10101010100001101010100101000010100000111011101001",
                  "10000000101100010000101100101101001011100000000100",
                  "10101001000000010100100001000100000100011110101001",
                  "00101001010101101001010100011010101101110000110101",
                  "11001010000100001100000010100101000001000111000010",
                  "00001000110000110101101000000100101001001000011101",
                  "10100101000101000000001110110010110101101010100001",
                  "00101000010000110101010000100010001001000100010101",
                  "10100001000110010001000010101001010101011111010010",
                  "00000100101000000110010100101001000001000000000010",
                  "11010000001001110111001001000011101001011011101000",
                  "00000110100010001000100000001000011101000000110011",
                  "10101000101000100010001111100010101001010000001000",
                  "10000010100101001010110000000100101010001011101000",
                  "00111100001000010000000110111000000001000000001011",
                  "10000001100111010111010001000110111010101101111000"};
struct node{
    int x,y,d;
    char pos;
};
node father[1562][1562];//当前节点的父节点;
bool vis[1562][1562];
int dx[4]={1,0,0,-1};
int dy[4]={0,-1,1,0};
void dfs(int x,int y)
{
    if(x==0&&y==0) return;
    else dfs(father[x][y].x,father[x][y].y);

    cout<<father[x][y].pos;//第一个输出的就是x=0,y=0的下一个情况
}
void bfs(int x,int y)
{
    queue<node> q;
    q.push({x,y,0});
    vis[x][y]=true;
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++)//按照 下 左 右 上 的字典序来走路
        {
            int a=t.x+dx[i],b=t.y+dy[i];
            if(a<0||b<0||a>29||b>49||vis[a][b]||maze[a][b]=='1') continue;
            q.push({a,b,t.d+1});
            vis[a][b]=1;
            //存储父节点的坐标
            father[a][b].x=t.x;
            father[a][b].y=t.y;
            if(i==0) father[a][b].pos='D';
            else if(i==1) father[a][b].pos='L';
            else if(i==2) father[a][b].pos='R';
            else if(i==3) father[a][b].pos='U';
        }
    }
}
int main()
{
    bfs(0,0);
    dfs(29,49);
}

六,差分与前缀和

1.大学里的树木要打药 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,c;cin>>n>>c;
    int ss=0;
    for(int i=0;i<c;i++)
    {
        int l,r,m;cin>>l>>r>>m;
        ss+=(r-l+1)*m;
    }
    cout<<ss<<endl;
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
int b[1000300];
int main()
{
    int n,c;cin>>n>>c;
    while(c--)
    {
        int l,r,value;cin>>l>>r>>value;
        b[l+1]+=value;
        b[r+1+1]-=value;
    }
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        b[i]=b[i]+b[i-1];
        sum+=b[i];
    }
    cout<<sum<<endl;
    return 0;
}

2.大学里的树木要维护 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;
int sum[30000];
int main()
{
    int n,q;cin>>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin>>sum[i];
        sum[i]=sum[i-1]+sum[i];
    }
    while(q--)
    {
        int l,r;cin>>l>>r;
        cout<<sum[r]-sum[l-1]<<endl;;
    }

    return 0;
}

七,构造

我理解的构造就是说找数学规律

1.找规律(不看)

image

#include<bits/stdc++.h>
using namespace std;
int x,y,z,n;
int main()
{
	cin>>n;
	cout<<n*2<<" "<<n*3<<" "<<n*6<<endl;
	return 0;	
} 

2.简答数论(找最大公约数)1246. 等差数列 - AcWing题库

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N];
int gcd(int a,int b)
{
    return b ? gcd(b,a % b) : a;
}
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n);
    //找d
    int d=0;
    for(int i=1;i<n;i++) d=gcd(d,a[i]-a[i-1]);
    //输出答案
    if (!d) printf("%d\n", n);
    else printf("%d\n", (a[n - 1] - a[0]) / d + 1);
    return 0;
}

3.思维题(不看)

image

image

八,并查集

代码思想:

image

image

第三个先别看:没理解

image

代码板子:

1.朴素并查集

const int N = 200010;
int p[N];
int find(int x)//已经带了路径压缩
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}
//初始化
for (int i = 1; i <= n; i++)
{
	p[i] = i;
}
//合并a和b所在的集合
p[find(a)] = find(b);

2.维护size的并查集  and  启发式合并维护size并查集

const int N = 200010;
int p[N],sz[N];
int find(int x)//已经带了路径压缩
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}
//初始化
for (int i = 1; i <= n; i++)
{
	p[i] = i;
    sz[i]=1;
}
//合并a和b所在的集合
p[find(a)] = find(b);
sz[find(b)]+=sz[find(a)];

const int N = 200010;
int p[N],sz[N];
int find(int x)//已经带了路径压缩
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}
//初始化
for (int i = 1; i <= n; i++)
{
	p[i] = i;
    sz[i]=1;
}
//所谓启发式合并:合并a和b所在的集合
//让小的集合去合并到大的集合
void merge(int a,int b)//让a作为小的合并到大的b上
{
    a=find(a);b=find(b);
    if(a!=b)
    {
        if(sz[a]>sz[b])
          swap(a,b);
        sz[find(b)]+=sz[find(a)];
        p[find(a)]=find(b);
        //sz[find(a)]+=sz[find(b)];
        //p[find(b)]=find(a);

    }
}

3.维护到祖宗节点距离的并查集

int p[N],d[N];
//p[]存储每个点的祖宗节点,d[x]存储x到p[x]的距离
//返回x的祖宗节点
int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=root;
    }
}
for(int i=1;i<=n;i++)
{
    p[i]=i;
    d[i]=0;
}
//合并连个集合
p[find(a)]=find(b);
d[find(a)]=distance;//根据具体问题,初始化find(a)的偏移量

例题:

1.836. 合并集合 - AcWing题库

#include<bits/stdc++.h>
using namespace std;
int n,m;
int fa[100033],siz[100033];
struct undoobject
{
    int pos,val;
    undoobject(int p,int v)
    {
        pos=p;
        val=v;
    }
};
stack<undoobject> undosize,undofa;
void init()
{
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        siz[i]=i;
    }
    while(!undosize.empty()) undosize.pop();
    while(!undofa.empty()) undofa.pop();
}
int find(int x)
{
    if(fa[x]==x) return x;
    return find(fa[x]);
}
//操作1
void merge(int u,int v)
{
    int x=find(u),y=find(v);
    if(x==y) return ;//在一个集合无需合并
    if(siz[x]<siz[y]) swap(x,y);//将y和并到x上
    
    undosize.push(undoobject(x,siz[x]));
    siz[x]+=siz[y];
    
    undofa.push(undoobject(y,fa[y]));
    fa[y]=x;
}
//操作2
bool chaxun(int x,int y)
{
    x=find(x),y=find(y);
    if(x==y) return true;
    else return false;
}
//操作3
void undo()
{
    siz[undosize.top().pos]=undosize.top().val;
    undosize.pop();
    fa[undofa.top().pos]=undofa.top().val;
    undofa.pop();
}
int main()
{
    cin>>n>>m;
    init();
    while(m--)
    {
        char q;cin>>q;
        if(q=='M')
        {
            int u,v;cin>>u>>v;
            merge(u,v);
        }
        else if(q=='Q')
        {
            int u,v;cin>>u>>v;
            if(chaxun(u,v)) cout<<"Yes"<<endl;
            else                    cout<<"No"<<endl;
        }
        else
        {
            undo();
        }
    }
    return 0;
}

2.带权重的并查集240. 食物链 - AcWing题库

总体框架

image

image

疑问详解

参考文档:

AcWing 240. 食物链—数组d的真正含义以及find()函数调用过程 - AcWing

ac码

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int n, m;
int p[N], d[N]; //p[]寻找祖宗节点,d[]求到祖宗节点的距离

int find(int x)
{
    if (p[x] != x)
    {
        int t = find(p[x]); // u暂时存一下p[x]根节点,辅助变量
        d[x] += d[p[x]];    // 更新距离
        p[x] = t;
    }
    return p[x];
}


// 不行,因为这个路径的长度(高度),是需要自上而下加起来的,从根节点往下走
// 所以要先调用递归

// int find(int x)
// {
//     if (p[x] != x)
//     {
//         d[x] += d[p[x]];    // 更新距离
//         p[x] = find(p[x]); 
//     }
//     return p[x];
// }

int main()
{
    scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; i ++ ) p[i] = i;

    int res = 0;//记录错误数
    while (m -- )
    {
        int t, x, y;
        scanf("%d%d%d", &t, &x, &y);

        if (x > n || y > n) res ++ ; // 当前的话中X或Y比N大,是假话
        else
        {
            int px = find(x), py = find(y); // 查找根节点
            if (t == 1) // 判断是否同类
            {
                if (px == py) {  // 若 x 与 y 在同一个集合中
                    if ((d[x] - d[y]) % 3) res ++ ; // 两数到根节点距离之差的模不为 0,说明不是同一类,是假话
                    // 其中 (d[x] - d[y]) % 3 不可写为 d[x] % 3 != d[y] % 3
                    // 因为 d[x], d[y] 可能为负数(一正一负),可改做 (d[x] % 3 + 3) % 3 != (d[y] % 3 + 3) % 3
                    // 负数 mod 正数为负数
                } else {    // 则 x 与 y 不在同一个集合中
                    p[px] = py;     // x 所在集合 合并到 y 所在集合
                    d[px] = d[y] - d[x];
                    // d[x] 的距离为什么不更新?
                    // 只是暂时不更新,在调用 find 时再更新
                }
            }
            else // X 是否吃 Y
            {
                if (px == py) {     // 若 x 与 y 在同一个集合中
                    // 若 X 吃 Y,则 d[x] 比 d[y] 大 1
                    if ((d[x] - d[y] - 1) % 3) res ++ ;  // 若距离之差 - 1 的模不为 0,说明吃不掉,是假话
                } else {    // 则 x 与 y 不在同一个集合中
                    p[px] = py;
                    // (d[x] - d[y] - 1) % 3 == 0
                    // d[x] + d[px] - 1 = d[y]  则:
                    d[px] = d[y] + 1 - d[x];
                }
            }
        }
    }

    printf("%d\n", res);

    return 0;
}

#include<bits/stdc++.h>
using namespace std;
int n,k;
int p[50022],d[50022];
void init()
{
    for(int i=1;i<=n;i++)
    {
        p[i]=i;
        d[i]=0;
    }
}
int find(int x)
{
    if(p[x]!=x)
    {
        int u=find(p[x]);
        d[x] += d[p[x]];
        p[x]=u;
    }
    return p[x];
}
int main()
{
    cin>>n>>k;
    init();
    int res=0;
    while(k--)
    {
        int t,x,y;cin>>t>>x>>y;
        if(x>n||y>n) res++;//直接不合理
        else
        {
            int px=find(x),py=find(y);
            if(t==1)
            {
                if((px==py)&&(d[x]-d[y])%3!=0)//先看看是否已经出现过了,这是出现过的情况
                {
                    res++;
                }
                else if(px!=py)
                {
                    p[px]=py;
                    d[px]=d[y]-d[x];
                }
            }
            else if(t==2)
            {
                if((px==py)&&(d[x]-d[y]-1)%3!=0)//先看看是否已经出现过了,这是出现过的情况
                {
                    res++;
                }
                else if(px!=py)
                {
                    p[px]=py;
                    d[px]=d[y]+1-d[x];
                }
            }
        }
    }
    cout<<res<<endl;
    return 0;
}

3.合根植物 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
const int N=1000020;
int p[N];
int m,n,k;
void init()
{
    for(int i=1;i<=N;i++)
    {
        p[i]=i;
    }
}
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
void merge(int a,int b)
{
    p[find(a)]=find(b);
}
int main()
{
    init();
    cin>>n>>m>>k;
    init();
    for(int i=1;i<=k;i++)
    {
        int a,b;cin>>a>>b;
        merge(a,b);
    }
    int ans=0;
    for(int i=1;i<=m*n;i++)
    {
        if(p[i]==i) ans++;
    }
    cout<<ans<<endl;
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N=1000020;
int p[N];
int siz[N];
int m,n,k;
void init()
{
    for(int i=1;i<=N;i++)
    {
        p[i]=i;
        siz[i]=1;
    }
}
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
void merge(int a,int b)
{
    a=find(a);
    b=find(b);
    if(a!=b)
    {
        if(siz[a]>siz[b])   swap(a,b); //让size小的a合到b上
        siz[find(b)]+=siz[find(a)];//一定要记住先写siz
        p[find(a)]=find(b);
    }
}
int main()
{
    init();
    cin>>n>>m>>k;
    init();
    for(int i=1;i<=k;i++)
    {
        int a,b;cin>>a>>b;
        merge(a,b);
    }
    int ans=0;
    for(int i=1;i<=m*n;i++)
    {
        if(p[i]==i) ans++;
    }
    cout<<ans<<endl;
    cout<<siz[19];
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int N=1000020;
int p[N];
int rk[N];
int m,n,k;
void init()
{
    for(int i=1;i<=N;i++)
    {
        p[i]=i;
        rk[i]=1;//这里可描述权重,边的大小
    }
}
int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}
void merge(int a,int b)
{
    a=find(a);
    b=find(b);
    if(a!=b)
    {
        if(rk[a]>rk[b])   swap(a,b); //让rk小的a合到b上
        p[a]=b;
        if(rk[a]==rk[b]) rk[b]++;
        //这里我解释一下我的疑惑为什么两个不相等的rk就不用变呢?
        //因为小的合到大的那么大的层数肯定还是不变
    }
}
int main()
{
    init();
    cin>>n>>m>>k;
    init();
    for(int i=1;i<=k;i++)
    {
        int a,b;cin>>a>>b;
        merge(a,b);
    }
    int ans=0;
    for(int i=1;i<=m*n;i++)
    {
        if(p[i]==i) ans++;
    }
    cout<<ans<<endl;
    return 0;
}

4.修改数组 - 蓝桥云课 (lanqiao.cn)

image

#include <iostream>
using namespace std;
int p[1000040];
int n;
void init()
{
    for(int i=1;i<=1000040;i++)
    {
        p[i]=i;
    }
}
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
void merge(int a,int b)
{
    p[find(a)]=find(b);
}
int main()
{
  //显然我想写双指针
  //但是这个题一定可以用不带路径压缩的并查集来查找~
  cin>>n;
  init();
  while(n--)
  {
      int t;
      cin>>t;
      t=find(t);
      cout<<t<<" ";
      merge(t,t+1);
  }
  return 0;
}

5.可撤销并查集

参考文档:【No.12】蓝桥杯可撤销并查集|查找|合并|撤销(C++)_在蓝桥王国中有个城市,王国经常会发生地震,会导致道路塌方,好在王国科技水平比较-CSDN博客

int n, q;
int fa[20000005], sz[2000005];

struct UndoObject
{
	int pos, val;
	UndoObject(int p, int v)
	{
		pos = p;
		val = v;
	}
};

stack<UndoObject> undo_sz, undo_fa;
//undo_sz,记录树的大小:记录每次连接操作的  较大的节点  和   较大的节点的大小
//undo_fa,记录它的父亲是谁:记录每次连接操作的 较小的节点的  原本的父节点

void init(int n)
{
	for (int i = 1; i <= n; i ++)
		fa[i] = i, sz[i] = 1;  //一棵点,就是自己
	while (!undo_sz.empty())
		undo_sz.pop();  //清除之前的栈的内容
	while (!undo_fa.empty())
		undo_fa.pop();  //清除之前的栈的内容
}
//

int find (int x)
{
	if (x == fa[x])
		return x;
	return find(fa[x]);
}
void merge(int u,int v)
{
    int x=find(u),y=find(v);
    if(x==y) return;
    if(siz[x]<siz[y])swap(x,y);//将y节点合到x节点上
    //把原值放入,存完以后改掉
    undo_sz.push(UndoObject(x,siz[x]))//这个是保留的源节点的大小信息
    siz[x]+=siz[y];
    //
    undo_fa.push(UndoObject(y,fa[y]))//这个保留了下面的操作
    fa[y]=x;
}

image

image

void undo()
{
	fa[undo_fa.top().pos]=undo_fa.top().val;
	undo_fa.pop();//这一次撤销操作完成
	siz[undo_sz.top().pos]=undo_sz.top().val;//这个是保留的
	undo_sz.pop();
}
把这道题:改一下命题写成操作三为撤销:836. 合并集合 - AcWing题库
#include<bits/stdc++.h>
using namespace std;
int n,m;
int fa[100033],siz[100033];
struct undoobject
{
    int pos,val;
    undoobject(int p,int v)
    {
        pos=p;
        val=v;
    }
};
stack<undoobject> undosize,undofa;
void init()
{
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        siz[i]=i;
    }
    while(!undosize.empty()) undosize.pop();
    while(!undofa.empty()) undofa.pop();
}
int find(int x)
{
    if(fa[x]==x) return x;
    return find(fa[x]);
}
//操作1
void merge(int u,int v)
{
    int x=find(u),y=find(v);
    if(x==y) return ;//在一个集合无需合并
    if(siz[x]<siz[y]) swap(x,y);//将y和并到x上
    
    undosize.push(undoobject(x,siz[x]));
    siz[x]+=siz[y];
    
    undofa.push(undoobject(y,fa[y]));
    fa[y]=x;
}
//操作2
bool chaxun(int x,int y)
{
    x=find(x),y=find(y);
    if(x==y) return true;
    else return false;
}
//操作3
void undo()
{
    siz[undosize.top().pos]=undosize.top().val;
    undosize.pop();
    fa[undofa.top().pos]=undofa.top().val;
    undofa.pop();
}
int main()
{
    cin>>n>>m;
    init();
    while(m--)
    {
        char q;cin>>q;
        if(q=='M')
        {
            int u,v;cin>>u>>v;
            merge(u,v);
        }
        else if(q=='Q')
        {
            int u,v;cin>>u>>v;
            if(chaxun(u,v)) cout<<"Yes"<<endl;
            else                    cout<<"No"<<endl;
        }
        else
        {
            undo();
        }
    }
    return 0;
}

image

九,二分法

整数二分

模板:789. 数的范围 - AcWing题库

#include<iostream>
#include<vector>
using namespace std;
vector<int> tmp;
int SL(int l,int r,int query)
{
    while(l<r)
    {
        int mid=l+r>>1;
        if(tmp[mid]>=query) r=mid;//if(绿) 口诀:后r美加一
        else l=mid+1;    
    }
    return l;
}
int SR(int l,int r,int query)
{
    while(l<r)
    {
        int mid=l+r+1>>1;
        if(tmp[mid]<=query) l=mid;
        else r=mid-1;
    }
    return l;
}
int main()
{
    int n,q;cin>>n>>q;
    for(int i=0;i<n;i++)
    {
        int a;cin>>a;
        tmp.push_back(a);
    }
    for(int i=0;i<q;i++)
    {
        //思考一下二段性,利用红绿线段进行思考
        //找sl就是找绿线段,也就是后面的那个
        //找sr就是找红线段,也就是红色的那一个
        int query;cin>>query;
        int sl=SL(0,tmp.size()-1,query),sr=SR(0,tmp.size()-1,query);
        if(tmp[sl]!=query) cout<<"-1 -1"<<endl;
        else cout<<sl<<" "<<sr<<endl;
    }
    return 0;
}

1.1.跳石头 - 蓝桥云课 (lanqiao.cn)枚举的距离

#include <bits/stdc++.h>
using namespace std;
int len,n,m;
const int N=50010;
int store[N];
bool check(int d)
{
    int num=0;//记录搬走的石头的数量
    int pos=0;//当前有几块石头
    for(int i=1;i<=n;i++)
    {
        if(store[i]-pos<d) num++;//移除的就会增多
        else       pos=store[i];//以这一块石头当作基准供下一轮使用
    }
    if(num<=m) return true;
    else       return false;
}
int main()
{
  cin>>len>>n>>m;
  for(int i=1;i<=n;i++) cin>>store[i];
  int l=0,r=len;
  while(l<r)
  {
      int mid=(l+r+1)>>1;
      if(check(mid))     l=mid;
      else         r=mid-1;
  }
  cout<<l<<endl;
  return 0;
}

2.1.分巧克力 - 蓝桥云课 (lanqiao.cn)枚举的分完后的边长

3.1.扫地机器人 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;

const int N=100050;
int robot[N];
int n,k;
bool check(int x)
{
    int s=0;//这里是指当前扫到的地理位置
    for(int i=1;i<=k;i++)
    {
        if(robot[i]-x<=s)
        {
            if(robot[i]<=s)//s已经大于robot[i]了,robot[i]只用扫右边的
                 s=robot[i]+x-1;
            else s+=x;
        }
        else//只扫左边不可行>s了
        {
            return false;
        }
    }
    if(s>=n) return true;
    else     return false;
}

int main()
{
    cin>>n>>k;
    for(int i=1;i<=k;i++)
    {
        cin>>robot[i];
    }
    sort(robot+1,robot+k+1);
    int l=0,r=n;
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else         l=mid+1;
    }
    cout<<(r-1)*2<<endl;
    return 0;
}

浮点数二分

1.790. 数的三次方根 - AcWing题库

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

int main()
{
    double n;cin>>n;
    double l=-10000,r=10000;
    while(r-l>1e-8)
    {
        double mid=(l + r) / 2;
        if(mid*mid*mid>=n) r=mid;
        else l=mid;
    }
    printf("%lf\n", l);
    return 0;
}

2.M次方数M次方根 - 蓝桥云课 (lanqiao.cn)

image

#include<bits/stdc++.h>
using namespace std;
double n,m;
double l,r;
double eps=1e-8;
bool pd(int a,int b)
{
    double c=1;
    while(b--)//比如b=3 a*a*a
    {
        c=c*a;
    }
    if(c>=n) return 1;
    else     return 0;
}
int main()
{
    cin>>n>>m;
    l=0,r=n;
    while(abs(l-r)>eps)
    {
        double mid=(l+r)/2;
        if(pd(mid,m)) r=mid;
        else          l=mid;
    }
    printf("%.7f",r);
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
double n;
double l,r,mid;
double eps=1e-8;
bool pd(double a,double b)
{
    double c=1;
    while(b--)//比如b=3 a*a*a
    {
        c=c*a;
    }
    if(c>=n) return 1;
    else     return 0;
}
int main()
{
    int m;
    cin>>n>>m;
    l=0,r=n;
    while(abs(l-r)>eps)
    {
        mid=(l+r)/2;
        if(pd(mid,m)) r=mid;
        else          l=mid;
    }
    printf("%.7f",r);
    return 0;
}

十,贪心

1.常见贪心问题

1.区间调度问题

image

image

2.区间覆盖问题

image

image

3.最优装载问题

image

image

4.多机调度问题

image

5.结构体排序代码

image

2.1.翻硬币 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
string aim;
string ori;
int ans;
void switch_1(int a)
{
    if(ori[a]=='*') ori[a]='o';
    else            ori[a]='*';
}
void switch_2(int a)
{
    ans++;
    switch_1(a);
    switch_1(a+1);
}

int main()
{
    cin>>ori;cin>>aim;
    int n=ori.size();
    for(int i=0;i<n;i++)
    {
        if(ori[i]!=aim[i]) switch_2(i);
        else continue;
    }
    cout<<ans<<endl;;
    return 0;
}

3.1.快乐司机 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
double ans=0;
struct goods{
    double weight;
    double value;
    goods(int w,int v)
    {
        weight=w;
        value=v;
    }
};
bool myguize(const goods &g1,const goods &g2)
{
    return (g1.value/g1.weight)>(g2.value/g2.weight);
}
vector<goods> yunshu;
int main()
{
    int n,hezai;cin>>n>>hezai;
    for(int i=1;i<=n;i++)
    {
        int a,b;cin>>a>>b;
        yunshu.push_back(goods(a,b));
    }
    sort(yunshu.begin(),yunshu.end(),myguize);
    vector<goods> a=yunshu;
    for(int i=0;i<n;i++)
    {
        if(a[i].weight<hezai)
        {
            hezai-=a[i].weight;
            ans+=a[i].value;
        }
        else if(a[i].weight>=hezai)
        {
            ans+=hezai*(a[i].value/a[i].weight);
            hezai=0;break;

        }
    }
    printf("%.1lf",ans);
    return 0;
}

4.1.防御力 - 蓝桥云课 (lanqiao.cn)//思路不会纯抄代码

image

#include <bits/stdc++.h>
using namespace std;
struct mydata{
    int id;
    int weight;
}a[2000040],b[200040];
bool cmpa(mydata x,mydata y)//对于a来说的排序
{
    //先按增加量排序:从小到大
    if(x.weight!=y.weight) return x.weight<y.weight;
    //再按字典序排序
    else     return x.id<y.id;
}
bool cmpb(mydata x,mydata y)//对于b来说的排序
{
    if(x.weight!=y.weight) return x.weight>y.weight;
    else     return x.id<y.id;
}
int main()
{
    int n1,n2;cin>>n1>>n2;
    for(int i=1;i<=n1;i++)  cin>>a[i].weight,a[i].id=i;
    for(int i=1;i<=n2;i++)  cin>>b[i].weight,b[i].id=i;
    sort(a+1,a+n1+1,cmpa);
    sort(b+1,b+n2+1,cmpb);
    string s1;cin>>s1;
    int idx=1,idy=1;
    for(int i=0;i<(int)s1.size();i++)
    {
        if(s1[i]=='1') cout<<"B"<<b[idy++].id<<endl;
        else           cout<<"A"<<a[idx++].id<<endl;
    }
    cout<<"E"<<endl;
    return 0;
}

5.1.答疑 - 蓝桥云课 (lanqiao.cn)//答案思路较为详细

image

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+20;
struct node{
    ll s,a,e;
    bool operator <(const node &x) const
    {
        return (s+a+e)<(x.s+x.a+x.e);
    }
};
vector<struct node> aa;
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        ll s,a,e;
        cin>>s>>a>>e;
        aa.push_back(node{s,a,e});
    }
    sort(aa.begin(),aa.end());
    ll ans=0;
    for(int i=0;i<n;i++)
    {
        ll s=aa[i].s,a=aa[i].a,e=aa[i].e;
        ans+=(n-i)*(s+a)+(n-i-1)*e;
    }
    cout<<ans;
    return 0;
}

6.找零问题 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;cin>>n;
    int a1=n/100;
    n=n%100;
    int a2=n/50;
    n=n%50;
    int a3=n/20;
    n=n%20;
    int a4=n/5;
    n=n%5;
    int a5=n/1;
    n=n%1;
    cout<<"100:"<<a1<<endl;
    cout<<"50:"<<a2<<endl;
    cout<<"20:"<<a3<<endl;
    cout<<"5:"<<a4<<endl;
    cout<<"1:"<<a5<<endl;
    return 0;
}

7.小B的宿舍 - 蓝桥云课 (lanqiao.cn)

#include <cstdio>
#include <iostream>
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int move[200];
//搬运次数
    int N;
    int T;
    cin>>T;
    while(T--)
    {
        //每次搬运的起点和终点
        int from, to;
        int maxAns=0;

        scanf("%d", &N);
        memset(move, 0, sizeof(move));
        for(int i = 0; i < N; i++)
        {
            scanf("%d%d", &from, &to);
//将房间号映射为走廊号
            from = (from - 1)/2;
            to = (to - 1)/2;
//确保from<to,C++使用:swap(from, to)
            if(from > to)
            {
                swap(from,to)
            }
//统计占用走廊情况,并统计最大值
            for(int j = from; j <= to; j++)
            {
                move[j]++;
                maxAns=max(maxAns,move[j]);//找重叠的
            }
        }
        cout<<maxAns*10<<endl;
    }
}

十一,动态规划

1.0跳跃 - 蓝桥云课 (lanqiao.cn)

#include <bits/stdc++.h>
using namespace std;
int n,m,sum=-0x3f3f3f3f;
const int N=105;
int nextt[9][2]={{0,1},{0,2},{0,3},{1,0},{1,1},{1,2},{2,0},{2,1},{3,0}};
int mapp[N][N];
void dfs(int x,int y,int value)
{
    value+=mapp[x][y];
    if(x==n&&y==m)
    {
        sum=max(sum,value);
        return;
    }
    for(int i=0;i<9;i++)
    {
        int tx=x+nextt[i][0];
        int ty=y+nextt[i][1];
        if(tx<=n && ty <=m)
            dfs(tx,ty,value);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>mapp[i][j];
    dfs(1,1,0);
    cout<<sum;
    return 0;
}


value[n+5][m+5]

dp(x,y)
{
    if(x==n&&y==m)
        return value[n][m]

    if(越界)
        return 负无穷

    value[x][y]=value[x][y]+max(dp(x+1,y)......,dp(2,1))
    return dp(x,y)

}

2.2409. 游戏中的学问 - AcWing题库

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL DP[3100][3100],mod;
int n,k;
int main()
{
    cin>>n>>k>>mod;
    DP[3][1]=2;
    for(int i=4;i<=n;i++)
    {

        for(int j=1;3*j<=i&&j<=k;j++)
        {
            DP[i][j]=DP[i-1][j]*(i-1)%mod;

            DP[i][j]=(DP[i][j]+DP[i-3][j-1]*(i-1)*(i-2))%mod;
        }
    }
    cout<<DP[n][k];
    return 0;
}

十二,图论

弗洛伊德算法1.蓝桥公园 - 蓝桥云课 (lanqiao.cn)

image

#include <bits/stdc++.h>
using namespace std;
int n,m,q;
const long long INF=0x7f7f7f7f7f7f7f7fLL;
const int N=405;
long long dp[N][N];
void floyd()
{
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
            }
        }
    }
}
int main()
{
    cin>>n>>m>>q;
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=n;i++)
    {
        int u,v;long long w;cin>>u>>v>>w;
        dp[u][v]=dp[v][u]=min(dp[u][v],w);//当发生重变的时候,取最小的
    }
    floyd();
    while(q--)
    {
        int s,t;
        cin>>s>>t;
        if(dp[s][t]==INF)   cout<<"-1"<<endl;
        else if(s==t)       cout<<"0"<<endl;
        else          cout<<dp[s][t]<<endl;
    }
    return 0;
}

代码#include <bits/stdc++.h>
using namespace std;
int n,m,q;
const long long INF=0x3f3f3f3f3f3f3f3fLL;
const int N=405;
long long dp[N][N];
void floyd()
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
}
int main()
{
    cin>>n>>m>>q;
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=n;i++)
    {
        int u,v;long long w;cin>>u>>v>>w;
        dp[u][v]=dp[v][u]=min(dp[u][v],w);//当发生重变的时候,取最小的
    }
    floyd();
    while(q--)
    {
        int s,t;
        cin>>s>>t;
        if(dp[s][t]==INF)   cout<<"-1"<<endl;
        else if(s==t)       cout<<"0"<<endl;
        else          cout<<dp[s][t]<<endl;
    }
    return 0;
}

十三,数论

模运算:1.刷题统计 - 蓝桥云课 (lanqiao.cn)

#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
    ll a,b,n;cin>>a>>b>>n;
    ll week=5*a+2*b;
    ll days=(n/week)*7;
    n%=week;
    if(n<=a*5) days+=n/a+(n%a?1:0);
    else{
        n-=a*5;days+=5;
        days+=n/b+(n%b?1:0);
    }
    cout<<days<<endl;
    return 0;
}

快速幂1.快速幂 - 蓝桥云课 (lanqiao.cn)

image

#include <iostream>
using namespace std;
typedef long long ll;
//原理
//b^p  mod k      =(b mod k)^p   mod k;
ll fastpow(ll b,ll n,ll k)
{
    ll ans=1;
    b = b % k;
    while(n)
    {
        if(n&1) ans=(ans*b)%k;//ans=(ans*b)
        b= (b * b) %k;//a= (a * a)
        n=n>>1;
    }
    return ans;
}
//解释
//例如pow(a,11)  1011
//1011      ans=b;    b=b^2;
//101       ans=b^3   b=b^4;
//10                  b=b^8;
//1         ans=b^11;
int main()
{
    ll b,n,k;cin>>b>>n>>k;
    cout<<fastpow(b,n,k)<<endl;
    return 0;
}

最大公约数和最小公倍数

#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)
{     
    return b? gcd(b, a%b):a; 
}

int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}

1.核桃的数量 - 蓝桥云课 (lanqiao.cn)

#include<bits/stdc++.h>
using namespace std;
//c++有默认的__gcd()函数
int lcm(int a, int b){ return a / gcd(a, b) * b;}
int main(){
    int a,b,c;    cin>>a>>b>>c;
    int k = lcm(a,b);
    cout<<lcm(k,c)<<endl;
    return 0;
}

素数实现

#include <iostream>
#include <cmath>

bool is_prime(long long n){
    if(n <= 1)
        return false; // 1不是素数
    for(long long i = 2; i <= sqrt(n); i++)
        if(n % i == 0)
            return false; // 能整除,不是素数
    return true; // 全不能整除,是素数
}

int main() {
    long long number = 29; // 例子:要检查是否为素数的数值
    if (is_prime(number))
        std::cout << number << " 是素数。" << std::endl;
    else
        std::cout << number << " 不是素数。" << std::endl;
    return 0;
}

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include<cstdio>
using namespace std;
const int N = 2 ^ 20 + 10;
int primes[N], cnt;//pri[i]表示存放的质数,cnt记录质数个数,全局变量默认是0
bool st[N];//记录是不是合数,全局变量默认false
void get_primes(int n)
{
	for (int i = 2; i <= n; i++)从 2 开始筛
	{
		if (!st[i])//如果没有被划掉(表示不是合数)就说明当前i是质数
		{
			primes[cnt++] = i;//从primes[0]开始存放
		}
		for (int j = 0; primes[j] * i <= n; j++)//开始枚举已记录的质数,利用这些质数划掉合数
		{
			//for循环里面,i * primes[j] <= n,首先要保证划掉的合数不能大于n,不然没意义
			st[primes[j] * i] = true;//划掉合数
			if (i % primes[j] == 0) break;              
            //如果i是质数,则最多枚举到自身中断
			//如果i是合数,则最多枚举到自身的最小质数中断
		}
	}
}
int main()
{
	get_primes(12);
	for (int i = 0; i < cnt; i++)
	{
		cout << primes[i] << " ";
	}
	cout << endl;
	return 0;
}
  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值