DFS
最短路能解决:边权固定
如果边权和经过点有关,相当于是有后效性,那么就需要dfs
组合:选择A,B,有一个附加代价C,这种情况只能搜索
缺点就在于枚举每一种可能性,时间复杂度贼大
1.状态表示
2.剪枝
最优答案(如果某个答案已经比最优答案差了就放弃)
记忆化剪枝(记搜)(还记得数位DP嘛)
可行性剪枝(字面意思,当前不可行了以后一定也不可行)
可以看出:
1、n很小
2、图上没有重边,因此边数????≤28
3、边与边之间相互独立,因此不需要考虑边与边之间的相互影响
4、如果图上出现一棵树,则已满足连通图的要求
5、根据提示及第3条,一张图连通的概率为:该图中所有边都不被淹没的概率相乘
根据第1条:搜索,考虑每条边是否加入连通块
根据第4条:只要连通图中出现了一棵树,其余边是否被淹没不对答案产生影响
根据第2条:总状态数为2^28=268435456,看起来可能会被卡
根据第1、4条:搜索中最多选择????−1条边,因此总状态数小于????_28^7="1184040"。
根据第3、5条:可以计算出一张图出现的概率
需要什么:
1、搜索
2、并查集判断连通性
简单的剪枝:
如果剩余的边数不够形成一棵树,则直接返回
建反图
原来不能同时存在的x和y有边,建反图之后就没边了
然后找最大团
先找一个点,往外扩展
对于一个点来说,只有和它有直接边的点才有可能与它构成团
就是一个剪枝,每一次经过一个点就把不可能的点都去掉
在一个点之后可能加入的序列中(默认序列点从小到大)
如果当前点的权值加上序列里所有点的权值都小于当前的答案,就剪枝
从i+1->i,最大答案就是i往前加上i+1
1.删点—序列
原来序列是123456
先dfs1,和它有边的点是356,tot=v[1]
然后找3,和它有边的点是6,tot=v[1]+v[3]
最后是6,没有和它有边的点tot=v[1]+v[3]+v[6]
然后把1删掉,序列变成23456
2.可行点—sum+tot<=ans
3.当前答案—ans[i]+tot<=ans
假如我们当前到了第i个点,这个点之前的点的ans都已经知道
我们枚举j是上一个点,如果ans[j]+tot<ans,那么j之前的点也不可行(因为ans一定<=j)
ans[i]表示从这个点开始搜的最大的权值和
tot表示当前搜到的最大团的权值和
Ans表示目前的最大的答案
Sum表示序列中剩下的点的权值和
那么为了能够当前答案剪枝,我们就需要把从1到n的序列倒过来dfs,即先算ans[n]
枚举每个位置的数,判断是否可以放
当前行未出现过
当前列未出现过
当前格子未出现过
更新进入下一层
判断是否出现可以使用二进制
TLE?
倒序枚举即可
BFS
优先扩展浅层节点状态逐渐深入
通常用队列实现
最重要的是判重,即合理的表示状态
新扩展出的节点如果和以前扩展出的节点相同,则这个新节点就不必再考虑
如何平衡时间和空间
状态(节点)数目巨大,如何存储?
怎样才能较快判断一个状态是否重复?
先排序(离散化)
Dis[x][y][t]表示在x,y,上一个线索是t的最小步数
queue<pair<int,int> > Q; int FindPath(pair<int,int> b,pair<int,int> e) { for (int i=0;i<n;++i) for (int j=0;j<m;++j) dis[i][j]=1e9+10; Q.push(b); dis[b.first][b.second]=0; while (!Q.empty()) { pair<int,int> u=Q.front(); Q.pop(); int x=u.first,y=u.second; for (int i=0;i<4;++i) { int tx=x+dx[i],ty=y+dy[i]; if (CoordValid(tx,ty) && mp[tx][ty]!=0 && dis[tx][ty]>dis[x][y]+1) { dis[tx][ty]=dis[x][y]+1; Q.push(make_pair(tx,ty)); } } } return dis[e.first][e.second]; }
记录当前素数的值
每次选择一个位置,将其该改为另一个数
检查新的数是否是素数
相当于移动到一个空位置花费为1、有守卫的位置花费为2
直接求最短路?
点数:????∗????≤40000
边数:????∗????∗2≤80000
直接求最短路可能超时,如何优化?
注意到边权只有1或2
为何不能直接BFS?
可以直接BFS求最短路的图边权只能是1。
只有边权为1才能保证在所有前驱结点都被扩展以后再扩展当前点
如何通过改变这个图使边权为1?
拆点?将每个点拆成一个入点一个出点?
增加了长度为0的边,可能导致错误
不能改变原有为1的边,如何特殊处理长度为2的边?
在到达‘x’点时,强制让当前点路径加1,将‘x’改为‘@’,不扩展当前点,使当前点重新入队。
为何不会影响最终答案?
由于路径长度为1:
其他点在重新进行扩展到达当前点时,最短路长度≥当前最短路长度+1
因此其他点无法更新当前点答案,最终答案因此也不会改变
Bfs本质是贪心?
队列是有序性,队首一定是最小的元素,队列是单增的序列,如果破坏了队列就不能
d+2-->d+1+1 移动和杀死守卫,杀死守卫相当于从队首移到队尾
假设农夫起始位于点3,牛位于5,N=3,K=5,最右边是6。
如何搜索到一条走到5的路径?
策略1)深度优先搜索:从起点出发,随机挑一个方向,能往前走就往前走(扩展),走不动了则回溯。不能走已经走过的点(要判重)。
要想求最优(短)解,则要遍历所有走法。
策略2)广度优先搜索:给节点分层。起点是第0层。从起点最少需n步就能到达的点属于第n层。
第1层:2,4,6
第2层:1,5
第3层:0
扩展时,不能扩展出已经走过的节点(要判重)
可确保找到最优解,但是因扩展出来的节点较多,且多数节点都需要保存,因此需要的存储空间较大