最短路能解决:边权固定优化
若是边权和通过点有关,至关因而有后效性,那么就须要dfsspa
组合:选择A,B,有一个附加代价C,这种状况只能搜索3d
缺点就在于枚举每一种可能性,时间复杂度贼大code
1.状态表示blog
2.剪枝排序
最优答案(若是某个答案已经比最优答案差了就放弃)队列
记忆化剪枝(记搜)(还记得数位DP嘛)class
可行性剪枝(字面意思,当前不可行了之后必定也不可行)扩展
能够看出:搜索
一、n很小
二、图上没有重边,所以边数𝑚≤28
三、边与边之间相互独立,所以不须要考虑边与边之间的相互影响
四、若是图上出现一棵树,则已知足连通图的要求
五、根据提示及第3条,一张图连通的几率为:该图中全部边都不被淹没的几率相乘
根据第1条:搜索,考虑每条边是否加入连通块
根据第4条:只要连通图中出现了一棵树,其他边是否被淹没不对答案产生影响
根据第2条:总状态数为2^28=268435456,看起来可能会被卡
根据第一、4条:搜索中最多选择𝑛−1条边,所以总状态数小于𝐶_28^7="1184040"。
根据第三、5条:能够计算出一张图出现的几率
须要什么:
一、搜索
二、并查集判断连通性
简单的剪枝:
若是剩余的边数不够造成一棵树,则直接返回
建反图
原来不能同时存在的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?
倒序枚举便可
优先扩展浅层节点状态逐渐深刻
一般用队列实现
最重要的是判重,即合理的表示状态
新扩展出的节点若是和之前扩展出的节点相同,则这个新节点就没必要再考虑
如何平衡时间和空间
状态(节点)数目巨大,如何存储?
怎样才能较快判断一个状态是否重复?
先排序(离散化)
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]; }
记录当前素数的值
每次选择一个位置,将其该改成另外一个数
检查新的数是不是素数
至关于移动到一个空位置花费为一、有守卫的位置花费为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
扩展时,不能扩展出已经走过的节点(要判重)
可确保找到最优解,可是因扩展出来的节点较多,且多数节点都须要保存,所以须要的存储空间较大