[蓝桥杯2016决赛]路径之谜
題目描述
小明冒充X星球的騎士,進(jìn)入了一個(gè)奇怪的城堡。城堡里邊什么都沒(méi)有,只有方形石頭鋪成的地面。
假設(shè)城堡地面是 n x n 個(gè)方格。
按習(xí)俗,騎士要從西北角走到東南角。可以橫向或縱向移動(dòng),但不能斜著走,也不能跳躍。
每走到一個(gè)新方格,就要向正北方和正西方各射一箭。(城堡的西墻和北墻內(nèi)各有 n 個(gè)靶子)
同一個(gè)方格只允許經(jīng)過(guò)一次。但不必走完所有的方格。
如果只給出靶子上箭的數(shù)目,你能推斷出騎士的行走路線(xiàn)嗎?
有時(shí)是可以的,比如圖中的例子。
本題的要求就是已知箭靶數(shù)字,求騎士的行走路徑(測(cè)試數(shù)據(jù)保證路徑唯一)
輸入
第一行一個(gè)整數(shù)N(0<N<20),表示地面有 N x N 個(gè)方格
第二行N個(gè)整數(shù),空格分開(kāi),表示北邊的箭靶上的數(shù)字(自西向東)
第三行N個(gè)整數(shù),空格分開(kāi),表示西邊的箭靶上的數(shù)字(自北向南)
輸出
一行若干個(gè)整數(shù),表示騎士路徑
為了方便表示,我們約定每個(gè)小格子用一個(gè)數(shù)字代表,從西北角開(kāi)始編號(hào): 0,1,2,3…
比如,上圖中的方塊編號(hào)為:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
樣例輸入
4
2 4 3 4
4 3 3 3
樣例輸出
0 4 5 1 2 3 7 11 10 9 13 14 15
代碼如下:
#include <iostream> #include <cstring> using namespace std; int dx[] = {0,0,1,-1},dy[] = {1,-1,0,0};//方向向量 const int N = 21; int mp[N][N];//存儲(chǔ)地圖編號(hào) bool st[N][N];//標(biāo)記地圖某格是否走過(guò)或者能不能走 int path[410];//存儲(chǔ)路徑,這個(gè)數(shù)組要開(kāi)大一點(diǎn),它搜索的時(shí)候可能有一次搜索會(huì)把全部格子都走了 int n; int flagx[N],flagy[N];//每走一格射的靶子,用來(lái)判斷與題目輸入的靶子是否相同 int tarx[N],tary[N];//題目輸入的靶子數(shù)目 int flagxs,flagys; void PrintPath(int index)//輸出結(jié)果函數(shù),也可以加入dfs中,就是加進(jìn)去的話(huà)代碼比較丑 {for (int i = 1;i<=index;i++){cout<<path[i]<<" ";}cout<<endl; }void dfs(int x,int y,int index)//搜索路徑 {if (x==n && y==n)//判斷是否到達(dá)終點(diǎn){for (int i = 1;i<=n;i++){if (flagx[i]==tarx[i]) flagxs++;if (flagy[i]==tary[i]) flagys++;}if (flagxs==n && flagys==n)//判斷到達(dá)終點(diǎn)后靶子數(shù)目是否相同{PrintPath(index);return ;}else{flagxs = 0;flagys = 0;return;}}for (int i = 0;i<4;i++){int xx = x+dx[i],yy = y+dy[i];if (st[xx][yy]) continue;flagx[xx]++;flagy[yy]++;path[index+1] = mp[xx][yy];st[xx][yy] = true;dfs(xx,yy,index+1);st[xx][yy] = false;flagx[xx]--;flagy[yy]--;} }int main() {cin>>n;for (int i = 1;i<=n;i++) cin>>tary[i];for (int i = 1;i<=n;i++) cin>>tarx[i];memset(st,1,sizeof(st));int k = 0;for (int i = 1;i<=n;i++)for (int j = 1;j<=n;j++){mp[i][j] = k++;st[i][j] = false;}st[1][1] = true;//標(biāo)記起點(diǎn)flagx[1] = 1;flagy[1] = 1;path[1] = 0;dfs(1,1,1);return 0; }可惜這樣暴搜超時(shí)了,無(wú)法AC,我們要想辦法剪枝。
剪枝優(yōu)化AC代碼如下:
#include <iostream> #include <cstring> using namespace std;int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0}; const int N = 21; int mp[N][N]; bool st[N][N]; int tarx[N], tary[N]; int n; int sum;//這條路線(xiàn)的總步數(shù) int path[410];void PrintPath(int index) {for (int i = 1; i <= index; i++) {cout << path[i] << " ";}cout << endl; }void dfs(int x, int y, int index) {if (index > sum)//當(dāng)它搜索的時(shí)候超過(guò)總步數(shù)(多走了),就說(shuō)明肯定不是走這條路,所以重新選路return;for (int i = 1; i <= n; i++) {if (tarx[i] < 0 || tary[i] < 0)//當(dāng)有靶子減沒(méi)了,也肯定是走錯(cuò)路了return;}if (x == n && y == n && sum == index) {//只有剛好到終點(diǎn),且走的步數(shù)與總步數(shù)相等,就說(shuō)明是這條路了PrintPath(index);return ;}for (int i = 0; i < 4; i++) {int xx = x + dx[i], yy = y + dy[i];if (st[xx][yy])continue;tary[yy]--;tarx[xx]--;st[xx][yy] = true;//記得標(biāo)記path[index + 1] = mp[xx][yy];dfs(xx, yy, index + 1);st[xx][yy] = false;//要記得"還原現(xiàn)場(chǎng)"tary[yy]++;tarx[xx]++;}}int main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> tary[i];sum += tary[i];}for (int i = 1; i <= n; i++)cin >> tarx[i];memset(st, 1, sizeof(st));int k = 0;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) {mp[i][j] = k++;st[i][j] = false;}st[1][1] = true;tary[1]--;//注意,剛開(kāi)始要把(1,1)位置的靶子先減掉tarx[1]--;path[1] = 0;dfs(1, 1, 1);return 0; }總結(jié)
以上是生活随笔為你收集整理的[蓝桥杯2016决赛]路径之谜的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: dnf起源版本魔法石任务攻略介绍。
- 下一篇: 换电这事成了!长安汽车官宣加入蔚来换电体