【课程资源】
【蚁群/遗传算法】
1、传统算法
2、蚁群/遗传算法+TSP/CVRP
车辆路径问题(Vehicle Routing Problem,VRP)车辆路线问题
贪心算法:
蚁群算法:
1、介绍:
2、基本原理:
3、 两个基本过程
(1)状态转移方程
(2)信息素更新模型
4、算法流程框架图
一 算法概念和复杂度
二 分治、递推
详解及经典例题 | 分治 | 分治算法总结 | 1h视频课解析 =hoster| 分治算法讲解 |
小明贴地板
过河卒
分析1、分析2、f[i][j]=max(f[i−1][j]+f[i][j−1],f[i][j])
#include <bits/stdc++.h>
#define N 99
using namespace std;
int dx[8]={-2,-1,1,2,2,1,-1,-2};
int dy[8]={-1,-2,-2,-1,1,2,2,1};//左上角开始逆时针
int main(){
int n,m,x,y;
bool flag[N][N]={};//标记是否可达数组
int a[N][N]={};
cin>>n>>m>>x>>y;
//将不可达位置 置1 马(x,y)
flag[x][y]=1;
for(int i=0;i<8;i++){
if(x+dx[i]>=0&&y+dy[i]>=0)
flag[x+dx[i]][y+dy[i]]=1;
}
/* 查看是否标记成功
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
cout<<flag[i][j];
cout<<endl;
} */
//路径数计算
a[0][0]=1;
for(int i=0 ;i<=n;i++)
for(int j=0;j<=m;j++){
if(flag[i][j]==0){
a[i][j]=max(a[i-1][j]+a[i][j-1],a[i][j]);
//a[i][j]=a[i-1][j]+a[i][j-1];
}
}
cout<<a[n][m]<<endl;//输出要换行
/*输出检验
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
cout<<a[i][j];
cout<<endl;
}
*/
return 0;
}
第K小的数-分治
棋盘覆盖
1-思路 | 2-百度-代码 | 3-思路 | 分治c++ |
fill填充数组
#include <bits/stdc++.h>
#define N 33
using namespace std;
int t=1;
int board[N][N];
//分治涂色
void chessBoard(int tr,int tc,int dr,int dc,int size){//tr-tc棋盘dr-dc特殊块
if(size==1) return;
int count=t++;
int s=size/2;
if(dr<tr+s&&dc<tc+s){//在左上角
chessBoard(tr,tc,dr,dc,s);
}
else{
board[tr+s-1][tc+s-1]=count;//填右下且变drdc
chessBoard(tr,tc,tr+s-1,tc+s-1,s);
}
if(dr<tr+s&&dc>=tc+s){//在右上角
chessBoard(tr,tc+s,dr,dc,s);
}
else{
board[tr+s-1][tc+s]=count;//填左下且变drdc
chessBoard(tr,tc+s,tr+s-1,tc+s,s);
}
if(dr>=tr+s&&dc<tc+s){//在左下角
chessBoard(tr+s,tc,dr,dc,s);
}
else{
board[tr+s][tc+s-1]=count;//填右上且变drdc
chessBoard(tr+s,tc,tr+s,tc+s-1,s);
}
if(dr>=tr+s&&dc>=tc+s){//在右下角
chessBoard(tr+s,tc+s,dr,dc,s);
}
else{
board[tr+s][tc+s]=count;//填坐上且变drdc
chessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main(){
int k,x,y,n;
cin>>k>>x>>y;//2^k、特殊棋盘坐标
n=pow(2,k);//棋盘大小
//int board[n][n];
fill(board[0],board[0]+n*n,-1);//-1覆盖
board[x][y]=0;
/*输出检验
for(int i=0;i<n;i++){
for (int j=0;j<n;j++)
cout<<board[i][j]<<" ";
cout<<endl;
}*/
chessBoard(0,0,x,y,n);
//show();
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("%4d",board[i][j]);
cout<<endl;
}
return 0;
}
小车问题
带图代码★ | 数学+二分√ | 数学解法| 数学-清楚 | 数学图解 |
数学做法、二分法
P1258小车问题 | 分治算法eg | 二分 | 思路★| 二分程序★ |
三 动态规划
最优子结构性质和重叠子结构性质
双十一的红包雨
【数塔问题】
数塔问题、动规数塔思路分析 ★★、数塔问题检索目录 | 数塔问题 |
如何理解动态规划、(“递归”是“动态规划”过程中使用的一种手段)|| 事实上,动态规划方法最重要的,是找到一个当前状态与前一状态对应的关系。因为在动态规划结构的问题中,当前状态会依赖于上一个状态。|| 数塔问题:dp(i, j) = Max( dp(i+1, j), dp(i+1, j+1 ) )+ f [ i ][ j ] ||
//#include <bits/stdc++.h> //库中max函数调用出问题
#include <iostream>
#include <algorithm>
#define N 1010
using namespace std;
int max2(int x,int y){
if(x>=y)
return x;
else
return y;
}
int max3(int x,int y,int z){
int m=x;
if(y>m)
m=y;
if(z>m)
m=z;
return m;
}
int main(){//类数塔问题 自下而上
int n,loc,time,value,maxt=-1;
int dp[N][11]={};//原始数据、动态最大红包
cin>>n;
for(int i=0;i<n;i++){//i表示时间j表示位置
cin>>loc>>time>>value;
dp[time][loc]=value;//初始化
//maxt=max(time,maxt);//最大时间
if(time>maxt)
maxt=time;
}
for(int i=maxt-1;i>=0;i--){//自下而上计算
//左边
dp[i][0]+=max2(dp[i+1][0],dp[i+1][1]);
//右边
dp[i][10]+=max2(dp[i+1][10],dp[i+1][9]);
//中间
for(int j=1;j<=9;j++){
//dp[i][j]+=max(max(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1]);
dp[i][j]+=max3(dp[i+1][j-1],dp[i+1][j],dp[i+1][j+1]);
}
}
cout<<dp[0][5]<<endl;
return 0;
}
状态转移 方程:dp[i][j]=max3(dp[i+1][j-1],dp[i+1][j],dp[i+1][j+1])+dp[i][j];
最大连续子段和
意思是:dp[]走完整段路,但是sum只保存最大的结果
int main(){
int n,a[N]={},dp[N]={},sum=0;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
dp[0]=a[0];//初始化
sum=a[0];
for(int i=1;i<n;i++){
dp[i]=max(a[i],dp[i-1]+a[i]);//更新,看看是我这一项本身最大,还是我加上前面更大
sum=max(sum,dp[i]);// 更新sum
}
cout<<sum<<endl;
}
减肥的小K/采中药
1-采药、要么采要么没采:max[n][m] = 较大值{max[n-1][m], max[n-1][m-time[n]]+value[n] }
int main(){
int T,M;//
int time[N]={},count[N]={},dp[N]={};
cin>>T>>M;//输入总时间和总草药数目
//输入采摘需要花费的时间&价值of每株
for(int i=1;i<=M;i++)
cin>>time[i]>>count[i];
//只要还有草药,就往包里装 ||动规不用排序哦
for(int i=1;i<=M;i++){
//有时间就扣除,倒计时
for(int j=T;j>=1;j--){
if(time[i]<=j){//如果摘第i棵草药的时间<所剩时间|√
//不摘i的时候-价值dp[j]-时间不变;摘了i价值就是dp[j-time[i]]剩下时间所得价值+count[i]
dp[j]=max(dp[j],dp[j-time[i]]+count[i]);//摘和不摘,谁大选谁
}
}
}
cout<<dp[T]<<endl;//时间T限制内采摘的药草
return 0;
}
最长公共子序列
四 贪心
种树问题
思路:1:一个数组tr[j]来记录每个区间内,j位置上是否种树。贪心:从右开始种树,这样下个区间就尽可能的会有上个区间的树。用ans来记录区间的树,与a[i].t进行比较,不满足最低要求就在tr[j]上种树,每种一棵树ans++,总计数count++,直到满足最低要求。第三个for是用来搜索区间开头到结尾的树的个数。||
struct node{
int bi,ei,t;
}a[30005];
int cmp(node a,node b){
if(a.ei==b.ei)
return a.bi<b.bi;
return a.ei<b.ei;
}
int main()
{
int h,n;
int count=0;
memset(tr,0,sizeof tr);
scanf("%d%d",&h,&n);
for(int i=0;i<n;i++)
scanf("%d%d%d",&a[i].bi,&a[i].ei,&a[i].t);
sort(a,a+n,cmp);
for(int i=0;i<n;i++)
{
int ans=0;
for(int j=a[i].bi;j<=a[i].ei;j++)
ans+=tr[j];
for(int j=a[i].ei;j>=a[i].bi&&ans<a[i].t;j--)//尽量从右开始种树
{
if(!tr[j])//如果tr[j]的位置上还没被种树的话,种树
{
tr[j]=1;
ans++;
count++;
}
}
}
printf("%d",count);
return 0;
}
区间问题
思想:1、区间我们先从区间的左端点开始考虑,然后我们先对所有线段排序,①以线段的起点为第一关键字,右端点为第二关键字,从小到大进行排序;那么我们②优先选择的第一条线段一定是左端点 <= 原始区间的左端点,然后线段的右端点要尽量的大于原始区间的左端点;这样当我们 选到了第一条最优的线段之后,我们再将③这条线段的右端点作为 新的区间的左端点;然后不断地迭代这个过程,如果④最终我们发现找到了最优的线段的右端点大于区间的右端点,就输出当前所选线段的总数。||
最小跳数
1、贪心+动规、算法分析 每次跳到当前位置可去范围的最大值 |
贪心就要每次都试图走的更远,意思并不是走到这一次所能走范围的最远,而是在这一次所能走范围里寻找下一次能走最远的位置。这样的策略就是竭力要走的更远。
#include<stdio.h>
int n,s[10000]={0},ct=0;
int bfs(int i)
{
int k,j=0,l,max=0;
if(i>=n-1) return 0; //找到便退出
k=s[i];ct++;
if(i+k>=n-1) return 0; //找到便退出
for(l=i+1;l<=i+k;l++) //for()找到下次能跳到最远的距离
{
if(max<=l+s[l]) //更新数据
{
j=l;max=l+s[l];
}
}
bfs(j); //跳到最远的数组里
}
int main()
{
int i;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&s[i]);
}
bfs(0);
printf("%d",ct); //打印步数
return 0;
}
2、最远 、每次都遍历当前位置所能到达的位置,跳到数字最大即可 ||
while(true)
{
//如果当前位置可以直接跳到终点
if(i+a[i]>=n-1)
{
count++;
break;
}
// 找到当前位置所能跳跃范围内最大的数
int maxn = -1, max_index;
for(int j=i+1; j<=i+a[i]; j++)
if(a[j]>maxn)
{
maxn = a[j];
max_index = j;
}
i = max_index; // 跳跃到最合适的位置
count++;
}
cout << count << endl;
return 0;
3、两种思路、
bool canJump(int* nums, int numsSize) {
numsSize--;
for (int i = 0; i < numsSize; i++) {
if (nums[i] + i >= numsSize) {//核心判断
numsSize = i;
i = -1;
}
}
if (numsSize)
return false;
return true;
}
五 搜索
填格子
N皇后
1、
N叉树=八皇后★、-递归非递归
可攻击同行同列对角、
示意图:
2、代码+思路 、列+对角线的能否放置位置判断&for循环控制行
禁忌搜索算法
资源
详解含实例
详解 | 介绍 | 入门 | 介绍及应用 |
禁忌搜索算法(Tabu Search,TS) C++代码思路with多参考
解决3SAT问题(C++实现)
C++旅行商问题 | TABU解决路线规划问题(CVRP | 31城市旅行商 | 30城市TSP | java-TS-旅行商 | 代码注释 | 带时间窗-java | 取送货
TS总结 | 浅谈TS√ | TS总结
基本原理和算法流程 | 一文搞懂TS | 超细讲解
现代优化算法
TS | 元启发之TS | 同 |
介绍 | 介绍 | 介绍 | 介绍
recommend-Tabu Search
python实现 | python实现 | 算法及pytho实现
车辆调度问题代码√
TS和相关算法 | 多算法 |
期末记录
判断:舍伍德、分治、
程序填空:过河卒、红包雨、贪心种树、广搜填充封闭区域
简答:①0-1背包与非0-1普通背包区别?分别使用什么方法②使用归并排序对一组数据进行排序;
程序设计:①CNN实现蔬菜图片识别②随机洗牌