之所以這道題我要寫題解,是因為解題的過程中我採用了多種方法(不嚴謹的說,基本寫完了搜尋裡的所有技巧)——bfs,ida* ,a*,雙向dfs。
這個過程很值得品味參考,於我來說也是一次不可多得的學習。
這道題的bfs思路是比較顯然的,**實現上也不算特別難。
#include#define debug printf("ok\n");
int f[10][10],dx[9]=,dy[9]=;
char op[5],ed[5];
struct node s,t;
namespace walkerv
void solve() ,t=(node);
std::queueq;
q.push(s),f[s.x][s.y]=0;
while(q.size()>0)
for(int i=1;i<=8;i++) );}}
} return;
} void print()
}int main()
return 0;
}
然後便是ida*。
如果你問我為什麼不先寫a*,因為這份**的重點是迭代加深,也就是id(iterative deepening)。但單打乙份迭代加深的dfs意義不大,所以就選擇用ida*。而且從各種角度來說,ida*都比a*要優秀一些。
但是這份**應該說是幾份**我調得最痛苦的乙份(大概前前後後修了三四個小時左右),最後的關鍵錯誤還是落在了估價函式上。
有必要說一下估價函式的設計:因為是馬在棋盤上的移動,所以考慮曼哈頓距離。我們知道馬每次移動的曼和頓距離為$3$,所以樂觀估計應當是當前位置到終點的曼哈頓距離除以$3$並向上取整。
#includeint max_dep;
int f[10][10],dx[9]=,dy[9]=;
char op[5],ed[5];
struct node s,t;
namespace walkerv
double estimate_function(int x1,int y1,int x2,int y2)
bool iddfs(int x,int y,int dep)
else
} //printf("x:%d y:%d g(x):%d f(x):%.1f\n",x,y,dep,estimate_function(x,y,t.x,t.y));
for(int i=1;i<=8;i++)
if(iddfs(x+dx[i],y+dy[i],dep+1))
}} return false;
} void solve() ,t=(node);
while(!iddfs(s.x,s.y,0))
return;
} void print()
}int main()
return 0;
}
在有了bfs和ida*的基礎上,a*就顯得非常容易了。
估價函式的設計與ida*是一致的。
#includeint f[10][10],dx[9]=,dy[9]=;
char op[5],ed[5];
struct node
}s,t;
namespace walkerv
double estimate_function(int x,int y)
void solve() ,t=(node);
s.est=estimate_function(s.x,s.y);
std::priority_queueq;
q.push(s),f[s.x][s.y]=0;
while(q.size())
for(int i=1;i<=8;i++) );}}
} return;
} void print()
}int main()
return 0;
}
對於這題,由於我們已經知道搜尋的初態和末態,所以既可以從初態搜到末態,也可以從末態搜到初態。
在此基礎上,雙向bfs的思路也就呼之欲出了——從初態和末態同時往中間搜尋(具體實現應當是正反各搜一輪)。
由於我們使用的是bfs,所以在輪流搜尋的時候但凡有乙個狀態被兩邊都搜尋到了(也就是說第乙個被兩邊都搜尋到的狀態),那麼這個狀態到初態和末態的路徑和就是答案(正確性顯然)。
此外,在**中需要注意的有如下兩點:
說句閒話,其實中間兩個佇列的實現那裡,如果用typedef寫會更好看一些,但是可讀性會大大降低(逃
#includeint ans;
int f1[10][10],f2[10][10],dx[9]=,dy[9]=;
char op[5],ed[5];
struct node s,t;
namespace walkerv
void solve() ,t=(node);
if(s.x==t.x&&s.y==t.y)
std::queueq1,q2;
q1.push(s),f1[s.x][s.y]=0;
q2.push(t),f2[t.x][t.y]=1;
while(q1.size()||q2.size())
else
for(int i=1;i<=8;i++)
f1[k.x+dx[i]][k.y+dy[i]]=f1[k.x][k.y]+1;
q1.push((node));
break;
case false:
if(f1[k.x+dx[i]][k.y+dy[i]])
f2[k.x+dx[i]][k.y+dy[i]]=f2[k.x][k.y]+1;
q2.push((node));
break;
} }}
} return;
} void print()
}int main()
return 0;
}
這次這道題碼下來,還算是收穫頗豐。誰會想到,乙個學了兩年多oi的人,直到這道題才算是摸透了上面四種演算法(包括bfs)。
此外,在寫**的時候,感覺到(id)a*是真正優秀的演算法。這不僅體現在它的執行時間上,而是說這種演算法是最貼近人類行為的。作為人類,我們在解決問題中面臨多種方式時,一定會略作估計並選取最優的方式進行嘗試。可能這也是啟發式演算法被廣泛運用到人工智慧裡的原因,畢竟我們人類定義的人工智慧就是與人類智慧型所相似的機器。
UVA439深搜和寬搜區別
這題其實就是乙個變種的寬搜,很簡單,可是後來發現自己把寬搜和深搜給記反了,這題就一直寫的是深搜,但是顯然寬搜的題用深搜做事不對的,也學可以,反正本弱不會,但是前面幾個深搜的題目,我都是用寬搜 做的,事實證明深搜的題目是可以用寬搜來做的,而深搜和寬搜的最主要區別就是深蒐用棧來實現,而寬蒐用 佇列來實現...
A 移動的騎士
time limit 1000 1000ms c others memory limit 65536 65536kb c others problem description somurolov先生是乙個西洋棋高手,他聲稱在棋盤上將騎士棋子從一點移動到另外一點,沒有人比他快,你敢挑戰他嗎?你的任務是...
白騎士的移動 搜尋
小s第一次接觸西洋棋。他發現西洋棋中的knight棋子的移動方式和中國象棋中的馬類似,移動方式如圖所示。於是小s在棋盤上隨意擺上了一些棋子,其中包括一枚白騎士 一枚黑皇后 若干黑戰車和若干黑主教。小s想知道,如何能在避開黑戰車和黑主教的攻擊範圍的前提下,花費更少的步數吃掉黑皇后。輸入格式 輸入僅包含...