首页 技术 正文
技术 2022年11月16日
0 收藏 854 点赞 3,532 浏览 4886 个字

一道关乎人生完整的问题。

DBFS的优越:避免了结点膨胀太多。

假设一个状态结点可以扩展m个子结点,为了简单起见,假设每个结点的扩展都是相互独立的。

分析:起始状态结点数为1,每加深一层,结点数An = An-1*m。假如搜索了i层找到终点,那么经过的结点数是O(i^m),如果从两边同时搜索,结点数是O(i^(m/2))。

极端情况,终点完全封闭。

DBFS的正确姿势:

图片来源:http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx

cdoj 414 八数码 (双向bfs+康拓展开,A*)

下面是原博客上的分析:

交替结点可能会因为扩展顺序而认为s-1-5-3-t是最短路。//这也可能得到正确结果,与结点的扩展顺序有关系

然而交替层次的做法才是正确的。

优化:提供速度的关键在于使状态扩展得少一些,所以优先选择队列长度较少的去扩展,保持两边队列长度平衡。这比较适合于两边的扩展情况不同时,一边扩展得快,一边扩展得慢。如果两边扩展情况一样时,加了后效果不大,不过加了也没事。

———————————-分割线——————————————————

DBFS的代码也是磕了好久想到怎么实现的。

加了奇偶剪枝和一些小优化

更新。经过仔细思考,简化了代码。

/*
Created by Rey Chen on 2015.7.5
*/#include<bits/stdc++.h>
using namespace std;//#define local
const int maxn = ;
int vis1[maxn];
int vis2[maxn];//保存距离起点的距离,初始值-1
int fac[];struct node
{
int e[];
int p;
int cod;//避免二次计算,初始值为-1
int code() {
if(~cod) return cod;
int Hash = ;
for(int i = ; i < ; i++) {
int cnt = ;
for(int j = i+; j < ; j++)
if(e[j] < e[i]) cnt++;
Hash += fac[-i] * cnt;
}
return cod = Hash;
}
int rev_value(){//用于奇偶剪枝
int res = , cnt ,i ,j;
for(i = ; i < ; i++) {
if(e[i]) {
cnt = ;
for(j = i+; j < ; j++)
if(e[j] && e[j] < e[i]) cnt++;
res += cnt;
}
}
return res;
}
};node start;
node ed;
int edHash;
int nodesz;
typedef vector<node>* vnodep;
vector<node> v1;
vector<node> v2;
vector<node> v3;
vector<node>:: iterator it,tmp_it;const int dx[] = {-, , , };
const int dy[] = { , ,-, };
bool ilegal[][];
void solve()
{
if(start.rev_value()&) { puts("unsolvable"); return; }//忽略0,操作不会改变逆序数总数的奇偶性。
int t;
t = start.code();
if(t == edHash) { puts("");return;}
memset(vis1,-,sizeof(vis1) );
memset(vis2,-,sizeof(vis2) );
vis1[t] = ;
vis2[edHash] = ; v1.clear(); v2.clear(); v3.clear();
vnodep q1 = &v1, q2 = &v2, nxt = &v3;
q1->push_back(start);
q2->push_back(ed);
int *V1 = vis1, *V2 = vis2;
while( !q1->empty() && !q2->empty() ) {
if(q1->size() > q2->size()) swap(q1,q2),swap(V1,V2); //化简代码的小技巧
for(it = q1->begin(), tmp_it = q1->end(); it != tmp_it ; it++){
node& u = *it;
node v;
for(int i = ;i < ;i++){
if(ilegal[u.p][i]) continue;
int np = u.p + dx[i]* + dy[i];
memcpy(&v,&u,nodesz); v.cod = -;//memcpy 比直接赋值要快
swap(v.e[np],v.e[u.p]);
if(!~V1[t = v.code()]){
V1[t] = V1[u.code()] + ;
if(~V2[t]){ printf("%d\n",V2[t]+V1[t]); return; }
v.p = np;
nxt->push_back(v);
}
}
}
q1->clear();
swap(q1,nxt);
}
puts("unsolvable");
}void init(){
fac[] = ;
for(int i = ; i < ; i++)
fac[i] = fac[i-]*i;
for(int i = ; i < ; i++)
for(int j = ; j < ; j++){
for(int k = ; k < ; k++)
if( (i == && k == ) || (i == && k == ) || (j == && k == ) || (j == && k == ) )
ilegal[i*+j][k] = true;
else ilegal[i*+j][k] = false;
}
}int main()
{
#ifdef local
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // local
char ch,s[];
init();
for(int i = ; i < ;i ++)
ed.e[i] = i+;
ed.e[] = ;
ed.p = ;
ed.cod = -;
edHash = ed.code();
nodesz = sizeof(ed); while(gets(s)) {
int j = ;
for(int i = ; i < ; i ++, j++) {
while(sscanf(s+j,"%c",&ch),ch == ' ')j++;
if(ch == 'x'){
start.e[i] = ; start.p = i;
}else {
start.e[i] = ch - '';
}
}
start.cod = -;
solve();
}
return ;
}

花了点时间写了A*。A*的关键在于估价函数,估价函数必须要小于实际值,越接近越好。

这里取的是除去x以后的曼哈顿距离。

这题为什么不需要两个表?需要open表是因为有可能有捷径的出现,这题不需要。

#include<bits/stdc++.h>
using namespace std;int t[],s[],Zero,tHashCode;
int fac[];
struct node
{
int p[], z, f, dist, hashCode;
bool operator < (const node& rhs) const {
return f > rhs.f || (f == rhs.f && dist > rhs.dist);
}
};inline int Hash(int *a)
{
int ans = ;
for(int i = ; i < ; i++) {
int cnt = ;
for(int j = i+; j < ; j++) if(a[j] < a[i]) cnt++;
ans += fac[-i] * cnt;
}
return ans;
}inline int Rev_value(int *a){
int ans = ;
for(int i = ; i < ; i++) {
int cnt = ;
for(int j = i+; j < ; j++) if(a[j] && a[j] < a[i]) cnt++;
ans += cnt;
}
return ans;
}
int Cost[][];//除去x之外到目标的网格距离和
//x 和 其他数交换,理想情况每次距离减一
inline void Manhattan(node &A)
{
A.f = A.dist;
for(int i = ; i < ; i++)if(A.p[i])
A.f += Cost[i][A.p[i]-];
}bool vis[];
const int dx[] = {-, , , };
const int dy[] = { , ,-, };
int dz[];
bool ilegal[][];void AstarBfs()
{
if(Rev_value(s)&) { puts("unsolvable"); return; }
node u;
u.hashCode = Hash(s);
if(u.hashCode == tHashCode) {puts(""); return;}
memset(vis,,sizeof(vis));
vis[u.hashCode] = ;
memcpy(u.p,s,sizeof(s));
u.dist = ;
u.z = Zero;
priority_queue<node> q;
Manhattan(u);
q.push(u);
while(q.size()) {
u = q.top(); q.pop();
if(u.hashCode == tHashCode) {printf("%d\n",u.dist);return;}
node v;
for(int i = ; i < ; i++) {
if(ilegal[u.z][i]) continue;
v.z = u.z + dz[i];
memcpy(v.p,u.p,sizeof(u.p));
swap(v.p[v.z],v.p[u.z]);
v.hashCode = Hash(v.p);
if(vis[v.hashCode]) continue;
vis[v.hashCode] = ;
v.dist = u.dist +;
Manhattan(v);
q.push(v);
}
}
puts("unsolvable");
}void init()
{
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
Cost[i][j] = (abs(i/-j/) + abs(i%-j%));
for(int i = ; i < ; i++)
t[i] = i+;
t[] = ;
fac[] = ;
for(int i = ; i < ; i++)
fac[i] = fac[i-]*i;
tHashCode = Hash(t);
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
for(int k = ; k < ; k++){
int nx = i+dx[k], ny = j + dy[k];
ilegal[i*+j][k] = !(nx>= && nx < && ny >= && ny < );
}
for(int k = ; k < ; k++) dz[k] = dx[k]* + dy[k];
}int main()
{
init();
char str[];
while(fgets(str,,stdin)) {
int j = ;
for(int i = ; i < ; i++, j++){
char ch;
while(sscanf(str+j,"%c",&ch),ch == ' ')j++;
if(ch == 'x'){
s[i] = ;Zero = i;
}else {
s[i] = ch - '';
}
}
AstarBfs();
}
return ;
}

附上数据生成器

#include<bits/stdc++.h>
using namespace std;int main()
{
srand( time( NULL ) );
char s[] ;
char ori[] = "";
int n = ;
int m = ;
int init = ;
for(int i = ; i < ; i++) next_permutation(ori,ori+);
for(int i=;i<n;i++)
{
for(int j = ;j<m;j++){
strcpy(s,ori);
s[] = 'x';s[] = '\0';
swap(s[],s[rand()%]);
for(int k = ;k < ; k++)
printf("%c%c",s[k],k==?'\n':' ');
}
next_permutation(ori,ori+);
}}

.bat

:loop
make.exe>data.txt
std.exe<data.txt>std.txt
my<data.txt>my.txt
fc my.txt std.txt
if not errorlevel 1 goto loop
pause
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,085
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,560
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,409
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,182
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,819
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,902