目录
声明:
本系列博客是《算法竞赛进阶指南》+《算法竞赛入门经典》+《挑战程序设计竞赛》的学习笔记,主要是因为我三本都买了按照《算法竞赛进阶指南》的目录顺序学习,包含书中的少部分重要知识点、例题解题报告及我个人的学习心得和对该算法的补充拓展,仅用于学习交流和复习,无任何商业用途。博客中部分内容来源于书本和网络(我尽量减少书中引用),由我个人整理总结(习题和代码可全都是我自己敲哒)部分内容由我个人编写而成,如果想要有更好的学习体验或者希望学习到更全面的知识,请于京东搜索购买正版图书:《算法竞赛进阶指南》——作者李煜东,强烈安利,好书不火系列,谢谢配合。
下方链接为学习笔记目录链接(中转站)
知识点归纳
位运算
快速乘,快速幂,各种按位运算,二进制状态压缩;
枚举、模拟、递推
能想象问题的“状态空间”,理解各种算法本质是对状态空间进行遍历和映射
递归
理解递归的思想、子问题、递归边界、回溯时还原现场
分治思想
二分
整数集合二分,实数域二分
单峰函数三分求极值
二分答案,把求解转化为判定
排序
各种排序算法:数据结构基础
离散化
中位数相关问题
求第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;
const ll mod=1e9+7;
const double EPS=1e-5;//-10次方约等于趋近为0
vector<int>a[50];
int n,m;
int val[50]