1.贪心
这个不讲了,根据题目来贪心就行了。
比如说取模后求 max
,从大往小枚举。
2.暴力
这种就很多方法了,举几个例子:
- 枚举(子集,染色等等)
- DFS/BFS
- 迭代加深搜索IDA*
- 折半搜索
- 双向宽搜
然后我们暴力时还可以剪枝,比较常见的有最优性剪枝,可行性剪枝,估价函数剪枝等等。
3.打表
一般来讲分为朴素打表和分段打表。
分段打表一般用于比较容易递推(可递推且依赖状态较少)的情况。
根据打表尝试推规律,这个就有点难了,凭感觉。
不过可以列一个类似于 f(i)=A*f(i-1)+B*f(i-2)+C*f(i-3)
之类的例子来列一下,看看能不能整出来。
还可以看看有没有积性函数的性质。
4.随机化/模拟退火
这个东西就比较强了,一般有这种性质的写了基本上有大分。
随机化,不言而喻,有些题目每次找到答案的概率较大(比如1/2或1/3),用随机化跑跑总没错。
然后,讲一下很 NB 的模拟退火:
模拟退火算法较适用于在较大或复杂的解空间中寻找近似全局最优解的优化问题,特别是当问题存在多个局部最优解,且传统贪心算法容易陷入局部最优时。
基本上板子不用改,背下来就好:
void mnth(){// 初始温度T0 终止温度Te 衰减系数Tx for(double t=1e4;t>1e-4;t*=0.99){int a=rand()%m+1,b=rand()%m+1;int now=calc();swap(e[a],e[b]);if(n+(e[n].x==10)==m){//满足约束条件int nxt=calc();//当前情况下的价值int delta=nxt-now;if(delta > 0){} else {if(exp(delta/t) < (double)rand()/RAND_MAX){swap(e[a],e[b]);}}}else swap(e[a],e[b]);}
}
max
改成 min
只需要把:
int delta=nxt-now;if(delta > 0){} else {if(exp(delta/t) < (double)rand()/RAND_MAX){swap(e[a],e[b]);}
}
改成:
int delta=nxt-now;if(delta < 0){} else {if(exp(-delta/t) < (double)rand()/RAND_MAX){swap(e[a],e[b]);}
}