0x08.基本算法 — 总结与练习

声明:
本系列博客是《算法竞赛进阶指南》+《算法竞赛入门经典》+《挑战程序设计竞赛》的学习笔记,主要是因为我三本都买了 按照《算法竞赛进阶指南》的目录顺序学习,包含书中的少部分重要知识点、例题解题报告及我个人的学习心得和对该算法的补充拓展,仅用于学习交流和复习,无任何商业用途。博客中部分内容来源于书本和网络(我尽量减少书中引用),由我个人整理总结(习题和代码可全都是我自己敲哒)部分内容由我个人编写而成,如果想要有更好的学习体验或者希望学习到更全面的知识,请于京东搜索购买正版图书:《算法竞赛进阶指南》——作者李煜东,强烈安利,好书不火系列,谢谢配合。


下方链接为学习笔记目录链接(中转站)

学习笔记目录链接


ACM-ICPC在线模板


知识点归纳

位运算

快速乘,快速幂,各种按位运算,二进制状态压缩;

枚举、模拟、递推

能想象问题的“状态空间”,理解各种算法本质是对状态空间进行遍历和映射

递归

理解递归的思想、子问题、递归边界、回溯时还原现场
分治思想

二分

整数集合二分,实数域二分
单峰函数三分求极值
二分答案,把求解转化为判定

排序

各种排序算法:数据结构基础
离散化
中位数相关问题
求第k大数的O(n)算法
归并排序求解逆序数对数

倍增

序列上的倍增算法及其应用
RMQ-ST算法

贪心

贪心的思想及其证明手段
多通过题目开拓视野,归纳总结


练习:

题目 提示
1.POJ 2965 枚举/位运算
2.CH 0802 模拟
3.POJ 2083 递归/分形
4.POJ 3714 分治/平面最近点对
5.CH 0805 二分
6.POJ 3179 二分/离散化/前缀和
7.CH 0807 排序/中位数/环形纸牌均分
8.POJ 1732 排序/中位数/货舱选址问题扩展
9.POJ 1220 高精度运算/进制转换
10.POJ 3045 贪心/邻项交换
11.POJ 1050 贪心
12.HDU 4864 贪心

1.AcWing116. 飞行员兄弟 (POJ 2965) (dfs/位运算状态压缩)

题目链接:https://www.acwing.com/problem/content/118/
在这里插入图片描述

1.DFS

正解应该是状态压缩,但是这里暴力dfs也能过。使用dfs主要是因为题目中 如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。要求答案排序选顺序最小的输出,所以从0,0开始dfs这样得到的答案一定是按照题目要求最小的那一组

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<stack>
#include<vector>

#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef pair<int,int> PII;

typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const int N=10;
const ll mod=1e9+7;
const double EPS=1e-5;//-10次方约等于趋近为0

int n,m;
char mp[N][N];
vector<PII>tmp,ans;

void turn_one(int x,int y){
   
    if(mp[x][y]=='+'){
   
        mp[x][y]='-';
    }
    else mp[x][y]='+';
}

void turn_all(int x,int y){
   
    over(i,0,3){
   
        turn_one(x,i);
        turn_one(i,y);
    }
    turn_one(x,y);//上面的xy多转了一次
}

void dfs(int x,int y){
   
    if(x==3&&y==4){
   //dfs必须上来就先判断边界
        bool flag=true;
        over(i,0,3)over(j,0,3){
   
            if(mp[i][j]=='+'){
   
                flag=false;
                goto hello;
            }
        }
        hello:;
        if(flag){
   //要先判空在size()
            if(ans.empty()||tmp.size()<ans.size()){
   
                ans=tmp;
            }
        }
        return;
    }
    if(y==4){
   
        x++,y=0;
    }
    //对于每个点分两种情况:turn或者不turn
    //turn:
    tmp.push_back({
   x,y});
    turn_all(x,y);
    dfs(x,y+1);
    tmp.pop_back();//回溯
    turn_all(x,y);
    //不turn
    dfs(x,y+1);
}

int main()
{
   
    over(i,0,3){
   
        scanf("%s",mp[i]);
    }
    dfs(0,0);
    printf("%d\n",ans.size());
    over(i,0,ans.size()-1){
   
        printf("%d %d\n",ans[i].first+1,ans[i].second+1);
    }
    return 0;
}

2.位运算+二进制枚举

作者:
秦淮岸灯火阑珊
链接:
https://www.acwing.com/solution/acwing/content/794/

算法标签:位运算+二进制枚举
解题思路:这道题目解题思路大致是,首先我们可以构造一个16位的二进制数,然后呢,二进制数的每一位代表4*4矩阵中的一位,例如1代表(1,1),2代表(1,2),3代表(1,3),4代表(1,4),5代表(2,1)。既然这样的话,那么我们只需要枚举这个16位的二进制数,就可以确定我们的方案,因为题目只需要最优解方案,所以时间复杂度大约是O(16 * 2^16)

2.AcWing.117. 占卜DIY (模拟)

在这里插入图片描述
输入样例:


8 5 A A
K 5 3 2
9 6 0 6
3 4 3 4
3 4 4 5
5 6 7 6
8 7 7 7
9 9 8 8
9 0 0 0
K J J J
Q A Q K
J Q 2 2
A K Q 2

输出样例:

9

模拟题。只要没有遇见K就一直移动牌
根据题意,每一张牌直接按照上面的数字放到第几堆里,以后就不会再变了,所以用sum数组记录有几张牌已归位。用val数组存当前这一堆牌还剩几张没有移位,移走一张牌实际上就是val[i]--。因为已经归位的牌是不会再动的了,所以不用放入vector里,不然就会WA。最后扫描一遍看有多少堆牌已归位,输出答案即可。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<stack>
#include<vector>

#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef pair<int,int> PII;

typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const int N=100007
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值