A*与IDA*
谨以此文向人工智能先驱,\(A\)*算法发明者\(Nils\ Nilsson\)致敬
推一篇深入研究的博客,而本文更多是粗略理解和习题吧。
\(A\)*算法是什么?它是启发式搜索的一种,即广度搜索算法\(bfs\)加上估价函数。
而\(IDA\)*则是另一种类似的启发式搜索,是迭代加深\(dfs\)加上估价函数。
迭代加深搜索是什么?就是每次限制\(dfs\)的深度进行搜索。
然后我们来讨论该算法的核心部分:估价函数
估价函数假设用\(h(x)\)表示,到达目前状态的代价用\(g(x)\)表示,那么估计的完成代价为\(f(x)=g(x)+h(x)\)。如果\(f(x)\)大于题目所需,那么可以进行剪枝。
需要注意的是,\(h(x)\)必须小于等于实际最优代价,满足此条件下越接近实际代价该估价函数越优。
一道例题:SCOI2005 骑士精神
对于一种状态,最佳的方案(运气最好时)是每次都能使一个骑士到达预定位置,最后一次能使一个骑士和一个空格到达预定位置,所以估价函数\(h(x)=\)棋盘上与目标状态不同的位置数\(+1\)。
然后搜索,注意每次改变空格的位置即可。
提供一份\(IDA\)*的代码
#include<bits/stdc++.h>
using namespace std;
const int dx[]={-2,-2,-1,-1,1,1,2,2}, dy[]={-1,1,-2,2,-2,2,-1,1};
const int tar[5][5]=
{
{2, 2, 2, 2, 2},
{1, 2, 2, 2, 2},
{1, 1, 0, 2, 2},
{1, 1, 1, 1, 2},
{1, 1, 1, 1, 1}
};
int sta[5][5];
inline int read()
{
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
int evoluate()
{
int res=0;
for (int i=0; i<5; i++)
for (int j=0; j<5; j++)
if (tar[i][j]^sta[i][j]) res++;
return res;
}
bool IDA(int x, int y, int dep, int maxdep)
{
int evo=evoluate();
if (dep+evo>maxdep+1) return false;
if (!evo) return true;
for (int i=0; i<8; i++)
{
int nx=x+dx[i], ny=y+dy[i];
if (nx>=0 && nx<5 && ny>=0 && ny<5)
{
swap(sta[x][y], sta[nx][ny]);
if (IDA(nx, ny, dep+1, maxdep)) return true;
swap(sta[x][y], sta[nx][ny]);
}
}
return false;
}
int main()
{
int T=read();
while (T--)
{
char s[5][5]; int X, Y;
for (int i=0; i<5; i++) scanf("%s", s[i]);
for (int i=0; i<5; i++)
for (int j=0; j<5; j++)
{
char c=s[i][j];
if (c=='0') sta[i][j]=1;
if (c=='1') sta[i][j]=2;
if (c=='*') X=i, Y=j, sta[i][j]=0;
}
int ans=-1;
for (int i=1; i<=15; i++)
if (IDA(X, Y, 0, i)) {ans=i; break;}
printf("%d\n", ans);
}
return 0;
}
一道类似的题:八数码难题
本题可以用\(IDA\)*和双向\(bfs\)通过,甚至\(map\)去重的\(bfs\)也可通过。作为一道练手题还是不错的。
代码不放了,和上题大体一致(我才不会说是我懒)
再看一个\(A\)*经典应用:\(K\)短路
(洛谷的模板题\(A\)*只能得到\(92pts\),标算是可持久化可并堆,所以这里就当是理性愉悦了吧)
说一下\(A\)*算法的思路。
先在反向图中\(Dijkstra\)得到估价函数\(dis(i)\)。
然后\(bfs\),用堆维护一下目前距离\(f(i)+dis(i)\)就可以了。
有一个没有什么用的优化,遍历每个点的次数不会超过\(\frac{w}{dis(1)}\),可以剪枝。
\(92pts\)代码
#include<bits/stdc++.h>
using namespace std;
const int N=5005, M=200005;
struct node{int to, nxt; double w;}edge1[M], edge2[M];
struct Node{int id; double w;};
struct NODE{int id; double w, f;};
bool operator < (Node a, Node b){return a.w>b.w;}
bool operator < (NODE a, NODE b){return a.f>b.f;}
int head1[N], head2[N], vis[N], cnt[N], cnt1, cnt2, n, m, ans;
double W, dis[N];
inline int read()
{
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
void add(int u, int v, double w)
{
edge1[++cnt1]=(node){v, head1[u], w};
head1[u]=cnt1;
edge2[++cnt2]=(node){u, head2[v], w};
head2[v]=cnt2;
}
void Dijkstra(int S)
{
priority_queue<Node> q; q.push((Node){S, 0});
for (int i=1; i<=S; i++) dis[i]=1e12; dis[S]=0.0;
memset(vis, 0, sizeof(vis));
while (!q.empty())
{
int u=q.top().id; q.pop();
if (vis[u]) continue; vis[u]=1;
for (int i=head2[u]; i; i=edge2[i].nxt)
{
int v=edge2[i].to; double w=edge2[i].w;
if (dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
q.push((Node){v, dis[v]});
}
}
}
}
void A_star(int S, int Max_cnt)
{
priority_queue<NODE> q; q.push((NODE){S, 0, 0});
while (!q.empty())
{
NODE u=q.top(); q.pop(); int x=u.id;
if (u.w>W) return;
cnt[x]++;
if (x==n) {ans++; W-=u.f; continue;}
if (cnt[x]>Max_cnt) continue;
for (int i=head1[x]; i; i=edge1[i].nxt)
{
int v=edge1[i].to;
q.push((NODE){v, u.w+edge1[i].w, u.w+edge1[i].w+dis[v]});
}
}
}
int main()
{
n=read(); m=read(); scanf("%lf", &W);
for (int i=1; i<=m; i++)
{
int u=read(), v=read();
double w; scanf("%lf", &w);
add(u, v, w);
}
Dijkstra(n); A_star(1, W/dis[1]);
printf("%d\n", ans);
return 0;
}
A*与IDA*的更多相关文章
- 逆向工程 - Reveal、IDA、Hopper、HTTPS抓包 等
目录: 一. iOS 如何做才安全 二.ipa文件 三.沙盒 中的数据 四.Reveal:查看 任何APP 的UI结构 五.反编译工具:IDA 六.反编译工具:Hopper Disassembler ...
- IDA的脚本IDC的一个简单使用
目的:主要是想学习一下IDA的IDC的脚本的使用.这里做了一个小的测试. 这里使用的是VS2015Community来生成文件的. 一.编写测试程序: 这里先生成我们的目标数据. 然后编写测试程序.得 ...
- 安卓动态调试七种武器之孔雀翎 – Ida Pro
安卓动态调试七种武器之孔雀翎 – Ida Pro 作者:蒸米@阿里聚安全 0x00 序 随着移动安全越来越火,各种调试工具也都层出不穷,但因为环境和需求的不同,并没有工具是万能的.另外工具是死的,人是 ...
- iOS程序逆向Mac下常用工具——Reveal、HopperDisassemble、IDA
原文在此 一.Reveal 1 一般使用 Reveal是ITTY BITTY发布的UI分析工具,可以很直观的查看App的UI布局.如下图所示: Reveal是需要付费的,需要89美元, ...
- IDA插件栈字符串识别插件
该插件是一款可以自动识别栈上局部变量为字符串的插件,字符串形式如下,并自动的加上注释 如图:可以自动识别栈上的字符串 项目主 ...
- Android动态方式破解apk进阶篇(IDA调试so源码)
一.前言 今天我们继续来看破解apk的相关知识,在前一篇:Eclipse动态调试smali源码破解apk 我们今天主要来看如何使用IDA来调试Android中的native源码,因为现在一些app,为 ...
- 计算机病毒实践汇总六:IDA Pro基础
在尝试学习分析的过程中,判断结论不一定准确,只是一些我自己的思考和探索.敬请批评指正! 1. IDA使用 (1)搜索.下载并执行IDA Pro,对可执行程序lab05-01.dll进行装载,分别以图形 ...
- IDA在内存中dump出android的Dex文件
转载自http://drops.wooyun.org/tips/6840 在现在的移动安全环境中,程序加壳已经成为家常便饭了,如果不会脱壳简直没法在破解界混的节奏.ZJDroid作为一种万能脱壳器是非 ...
- IDA来Patch android的so文件
在上文中,我们通过分析定位到sub_130C()这个函数有很大可能性是用来做反调试检测的,并且作者开了一个新的线程,并且用了一个while来不断执行sub_130C()这个函数,所以说我们每次手动的修 ...
- Ida动态修改android程序的内存数据和寄存器数值,绕过so文件的判断语句
我们继续分析自毁程序密码这个app,我们发现该程序会用fopen ()打开/proc/[pid]/status这个文件,随后会用fgets()和strstr()来获取,于是我们在strstr()处下个 ...
随机推荐
- Android中fragment之间和Activity的传值、切换
功能介绍:通过一个activity下方的三个按钮,分别是发送消息(sendButton).聊天记录(chatButton).常用语(commonButton).当单击按钮是,来切换上方的fragmen ...
- EditText输入小数
edtValue.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
- CSS-弹性布局-伪类选择器-复杂选择器
1.定位 1.堆叠顺序 一旦将元素变为已定位元素的话,元素们则有可能出现堆叠的效果. 如何改变堆叠顺序? 属性:z-index 取值:无单位的数字,数字越大越靠上. 注意: 1.父子元素间,z-ind ...
- 2019.01.01 bzoj3625:小朋友和二叉树(生成函数+多项式求逆+多项式开方)
传送门 codeforces传送门codeforces传送门codeforces传送门 生成函数好题. 卡场差评至今未过 题意简述:nnn个点的二叉树,每个点的权值KaTeX parse error: ...
- 安装配置ftp服务器
1.安装ftp服务 检查是否安装vsftpd rpm -qa|grep vsftpd 安装 vsftpd yum -y install vsftpd 2.配置 编辑 文件 /etc/vsftpd/vs ...
- tomcat7 安装 windows 服务
tomcat 可以安装成windows 服务,这样 每次启动就不需要启动tomcat了. 具体配置: 1.修改 service.bat 在行首添加 set "JAVA_HOME=E:\jdk ...
- CEdit控件[转]
1.CButton.CEdit等从CWnd继承了重要的功能: 使用CWnd::SetWindowText和CWnd::GetWindowText可以设置和获得窗口或控件上的文本.CWnd::SetFo ...
- vue动态路由
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件.例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染.能够提供参数的路由即为动态路由第一步:定义组件 c ...
- C# 编码标准(三)
一.代码注释 1.文档型注释 该类注释采用.Net已定义好的Xml标签来标记,在声明接口.类.方法.属性.字段都应该使用该类注释,以便代码完成后直接生成代码文档,让别人更好的了解代码的实现和接口.[示 ...
- SGU 271 Book Pile (双端队列)
题意:n,m,k,表示有一个长度为 n 的序列,有 m 个操作,操作有 2 种,第一种是 ADD 在前面添加一个串,第二种是把前 k 个进行翻转,问你最后的序列是什么样的. 析:很明显,如果直接模拟, ...