第五讲---搜索和动态规划
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Q
((1,1) (2,3))
3. (回溯方法 )
((1,1))
Q Q
((1,1) (2,3)) ((1,1) (2,4))
3. (回溯方法 )
((1,1))
Q Q Q
((1,1) (2,3)) ((1,1) (2,4))
((1,1) (2,4) (3.2))
3. (回溯方法 )
((1,1))
Q Q
如果*想碰到@,需要多少步。 DFS写写看吧。 Bfs用队列。
Hdu 3220 Alice’s Cube
上海赛区的题目,清华10+分钟过的题目,全 场100+多队,几乎所有的队伍都过的题目, 但是做出来的速度却相差很多。40分钟内写出 来,并一次ac的。 Hdu 3220,会的可以去写写。 Bfs+位压缩。
Fzu 1004
For(i=n;i>=1;i--) For(j=1;j<=I;j++) dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]); 输出dp[0][0]
不得不说的另一个例子:背包问题
Hdu 2602 Bone Collector http://acm.hdu.edu.cn/showproblem.php?pid =2602
((1,1) (2,4) (3.2))
3. (回溯方法 )
((1,1))
((1,2))
Q
Q
Q
((1,1) (2,3)) ((1,1) (2,4)) ((1,2) (2,4))
((1,1) (2,4) (3.2))
((1,2) (2,4) (3,1))
3. (回溯方法 )
((1,1))
((1,2))
0-1 背包
题目模型: N个物体:两个属性:重量和价值 如上:5个物体,背包容量10个重量 5个物体的价值:1 2 3 4 5 重量 54321 如何选取其中的物体,使价值和最大,当然重 量又不能超过背包的最大允许量。
动态规划
每次加入一个物体的考虑,只有取与不取的情况, 保留最大值。弄懂思想代码很短。初次接触则 不好懂n个物体,m的背包容量 for(i=0;i<n;i++) for(j=m;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
动态规划写法
for(i=0;i<n;i++) { for(j=0;j<=i;j++) { if(j==0 || i==j) C[i][j] = 1; else C[i][j] = C[i-1][j] + C[i-1][j-1]; } }
区别
动态规划往往效率很高。而递归写法,由于层 层递归,速度很慢。当n,m=(30,15)的 时候,得出结果就需要好几秒了,如果n,m= (100,50)发现时间上等的超出我们的耐性 了。而动态规划只是100*50的数组处理,马 上就有结果。 动态规划,要想好动态规划的方程,几乎每场 比赛都有1题。
Pku 1088 滑雪
http://acm.pku.edu.cn/JudgeOnline/problem? id=1088 记忆化搜索,对于dfs(int x,int y) 如果dp[x][y]==-1 进行计算,不然返回dp[x][y] 计算时,dp[x][y]=max( dfs(x-1,y),dfs(x+1,y),dfs(x,y-1),dfs(x,y+1) )+1; (如果周围比它小的话)
树
搜索到有@的点,当树层数稍微多时,指数级 增长复杂度. !
# (
条件剪枝!
(
*
#
)
*
#
$
(
!
)
(
@
递归: 回溯方法
例:皇后问题
Q Q
Q
Q
Biblioteka Baidu
3. (回溯方法 )
3. (回溯方法 )
((1,1))
Q
3. (回溯方法 )
((1,1))
Q Q
((1,1) (2,3))
3. (回溯方法 )
((1,1))
做法两种
1:记忆化bfs,用一张二维表,存到达每个点 所要的最短步数,初始化为inf(无穷大);每次用 bfs到达的步数如果小于该点的原值,更新, 并入队。直到队列为空; 2:优先队列,每次选取步数最少的点出来, 第一次到达目标点的步数就是最小步数。
Bfs 用到的stl。
#include<queue> Struct node {int x,int y,int num;} queue<node>q2; priority_queue<node>q1; 可以自动选取优先级最高的点出来扩展。比如 上题中的消耗体力最少的点出来扩展。提高效 率。
递归:dfs(int row,int val,int plus,int min); 建立一个数组,暴力填写+和- ,最后判断是 否合法。合法就num++。 这个思路很容易想到,想到后马上看数据范围, n<=24,貌似不大。暴力写写,挂了。 打表吧。还是不行,跑不出结果怎么打表,囧 剪枝!!计算出一共会有多少个+,这样一旦 +或者- 的数量超过这个数,就可以回溯了。
如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数 字和是相等的:
{1,6,7} and {2,3,4,5} {注 1+6+7=2+3+4+5} {2,5,7} and {1,3,4,6}
无穷背包
只要从小往大dp就行了 for(i=0;i<n;i++) for(j=0;j<=m;j++) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
USACO2.2 Subset Sums
题目如下: 对于从1到N的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的。 举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相 等的: {3}and {1,2} 这是唯一一种分发(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总 数)
((1,1) (2,4) (3.2))
3. (回溯方法 )
((1,1))
((1,2))
Q
((1,1) (2,3)) ((1,1) (2,4))
((1,1) (2,4) (3.2))
3. (回溯方法 )
((1,1))
((1,2))
Q Q
((1,1) (2,3)) ((1,1) (2,4)) ((1,2) (2,4))
n<=24
#include<iostream> using namespace std; int a[]={0,0, 0, 4,6,0, 0, 12,40,0, 0, 171,410,0, 0, 1896,5160,0, 0, 32757,59984,0, 0, 431095,822229}; int main() { int n; while(cin>>n,n)cout<<n<<""<<a[n]<<endl; return 0; }
广度优先搜索
Bfs 用在地图搜索的非 常多。 如何提高效率。以题目 而定。 常用:优先队列优化。 就是(堆) 例子:
草地 -2 雪地 -3 雪地 -3
平地 -1 平地 -1 雪地 -3
草地 -2 平地 -1 草地 -2
草地 -2 雪地 -3 平地 -1
Bfs 简介
Bfs 用队列的思想,先进先出。 Hdu 1242 Rescue http://acm.hdu.edu.cn/showproblem.php?pid =1242
A*算法
动态规划
不得不说的例子:数字三角形
动态规划与递归
动态规划思想: 求c(n,m); 递归写法: int c(int n,int m) { if(m==0)return 1; if(m==1)return n; if(n==m)return 1; return c(n-1,m-1)+c(n-1,m); }
递归
#include<iostream> using namespace std; int f(int x) { if(x<=1)return 1; else return f(x-1); } int main() { int x; while(cin>>x) cout<<f(x)<<endl; return 0; }
搜索与动态规划 《基础》
深度优先搜索
深度优先搜索属于图算法的一种,英文缩写为DFS即 Depth First Search.其过程简要来说是对每一个可能 的分支路径深入到不能再深入为止,而且每个节点只能 访问一次.
递归,回溯,暴力。 就像走迷宫,走遍任何一条路径,碰到死路。 走不了了,就回头找到最近的分叉路,走另一条。以 此类推,直到找到出口。所以相当暴力,基本上比赛 不会出太赤裸裸的暴力搜索。 用暴力搜索的要小心的估算复杂度,不轻易写。
http://acm.hdu.edu.cn/showproblem.php?pid=3220
题目大意:
给定一个几何体,每个点都有一个值, 0或者1,每次可以把线段相邻的两个 点的值互换,问需要几步,可以让 1-8号节点是0,而9到16号为1
做法
首先,肯定要很认真的看清哪些点是相邻的, 为了提高ac率,要检查两三遍。 比赛场上有人没用位压缩的,肯定超时了,后 来跑了很久后,终于打表过。浪费很多时间。 对于16个点,int 有32位,我们可以令每一位 对应好节点号,比如3 就是0..011这样每次送 入队列的只是一个数字,这个数字就能用16个 点的信息,如果用结构体,里面再定义bool flag【16】,就会超时。
做法
未压缩的目标状态:256-1=255 初始态:自己用二进制转十进制法转得到x; struct node {int num;int zt;}; 用到stl <queue> 开始时s.num=0; s.zt=x;
做法(伪代码)
Q.push(s); While(!q.empty()) { Tmp=q.front(); Q.pop(); 该变一步,得到tmp2 tmp2.num=tmp1.num+1,q.push(tmp2); If(tmp2.zt=目标状态){打印num;break;} }
推荐题目:
Foj: 1408 1734 1543
广度优先搜索bfs breadth-first search
@ 16 12 20 14 7 4 11 19 5 1 * 3 10 13 6 2 9 18 21 15 8 17
Struct node{ Int x; Int y; Int num; } Bool flag[100][100];
Q
Q
Q
((1,1) (2,3)) ((1,1) (2,4)) ((1,2) (2,4))
Q
((1,1) (2,4) (3.2))
((1,2) (2,4) (3,1))
((1,2) (2,4) (3,1) (4,3))
3. 回溯方法
递归的思想:
当前状态
目标状态g
Hdu 2510 符号三角形 http://acm.hdu.edu.cn/showproblem.ph p?pid=2510
符号三角形的 第1行有n个由“+”和”-“组成的符号 ,以后每行 符号比上行少1个,2个同号下面是”+“,2个异 号下面是”-“ 。 计算有多少个不同的符号三角形,使其所含”+“ 和”-“ 的个数相 同 。 n=7时的1个符号三角形如下: ++-+-++ +----+ -+++-++-+-+
怎么做
Priority_queue
其实就是《数据结构》将会学到的“堆”,能 在log级的复杂度内找到最小的值,并调整堆。 自己写堆效率较高,代码量大。且复杂容易出 错。一般情况下stl的这个函数效率也足够高了。 很方便。 结构体小于号重载后,每次选取步数最小的点 出来。
Bfs 题目:
Fzu 1205 Poj 1724 Hdu 2267
((1,1) (2,3)) ((1,1) (2,4))
((1,1) (2,4) (3.2))
3. (回溯方法 )
((1,1))
Q
((1,1) (2,3)) ((1,1) (2,4))
((1,1) (2,4) (3.2))
3. (回溯方法 )
((1,1))
((1,1) (2,3)) ((1,1) (2,4))