第一反應是搜尋題,想了一下如果用bfs的話,由於狀態過多,可能超記憶體,因此我用的dfs。
這裡我們討論一下剪枝條件:
如果當前狀態有一種顏色的數量小於3,那麼這種顏色就無法被消除,因此我們可以提前退出迭代。
如果兩個連著的方塊顏色是相同的話,我們不用交換。
如果兩個非空的方塊交換,我們只用考慮左邊那個方塊右移,而不用考慮右邊方塊左移的情況,這樣就能做到右移優先。
如果乙個方塊是空的,它的右邊非空,我們就只用考慮它右邊的方塊左移,當列舉到它右邊方塊的時候也不需要再考慮左移的情況。
注意下落清除方塊的時候要寫成迴圈形式,因為清除方塊以後,下落形成的新圖形可能又出現了能清除的方塊。
下面是我第一次寫的下落的程式,有乙個bug,如果上方多個方塊連在一起,而最下面方塊的下面是空的,根據我的最先寫的程式,只有最下面的乙個方塊會往下掉,因此我們要一列一列的列舉,把目標狀態先求出來
void drop()
void drop()//改進後的**
for(int x = 0; x < 5; x++)
for(int y = 0; y < 7; y++)
st[x][y] = num[x][y] == -1?0:st[x][num[x][y]];
return;
}
到了這裡,這道題的思路就很簡單了,就是寫的時候有點坑爹
#include#include#include#includeusing namespace std;
struct t
ans[10];
int st[10][10];
int n;
bool empty()//判斷是否全部消除完
void drop()//下移
for(int x = 0; x < 5; x++)
for(int y = 0; y < 7; y++)
st[x][y] = num[x][y] == -1?0:st[x][num[x][y]];
return;
}bool clear()//清除合法的聯通塊,本題的難點
}for(tx = x; tx <= x2; tx++)
st[tx][y] = 0;
flag = 1;
}} for(int x = 0; x < 5; x++)
for(int y = 0; y < 5; y++)
if(st[x][y])
}for(ty = y; ty <= y2; ty++)
st[x][ty] = 0;
flag = 1;
}} if(flag) return true;
else return false;
}void dfs(int step)
exit(0);
} return; }
int sum[12];
memset(sum,0,sizeof sum);
for(int x = 0; x < 5; x++)//如果乙個數它的個數已經小於3了,則不能被消除
for(int y = 0; y < 7; y++)
sum[st[x][y]]++;
for(int i = 1; i <= 10; i++)
if(sum[i] != 0&&sum[i] < 3) return;
for(int x = 0; x < 4; x++)
for(int y = 0; y < 7; y++)
if(st[x][y] != st[x+1][y])//顏色相同的就不用交換了 }
int main()
} dfs(1);
printf("-1\n");
return 0;
}
NOIP2011 Mayan遊戲 題解
mayan puzzle是最近流行起來的乙個遊戲。遊戲介面是乙個7行5列的棋盤,上面堆放著一些方塊,方塊不能懸空堆放,即方塊必須放在最下面一行,或者放在其他方塊之上。遊戲通關是指在規定的步數內消除所有的方塊,消除方塊的規則如下 1 每步移動可以且僅可以沿橫向 即向左或向右 拖動某一方塊一格 當拖動這...
NOIP2011 Mayan遊戲 搜尋
乙個有效的剪枝是排除等效冗沉,當兩種操作形成等效效果時不重複搜尋 若有兩個塊,那麼左邊的右移和右邊的左移是等效的,由於題意認為右移優先於左移,所以這種情況只取右移,而乙個塊左邊是空的時候則要嘗試左移 在回溯法 還原 的時候,可以先複製出來局面,在函式裡開陣列 別用全域性的,要儲存多個局面 然後複製回...
noip2011 Mayan遊戲 dfs 模擬
能力太弱啊,調了一天。首先我bfs掛了,因為狀態太多而mle,好像只能dfs,然後bfs改dfs過程中傻x錯誤一大堆。這道題主要是模擬比較麻煩,消除塊的情況非常複雜。剪枝的話,如果乙個塊左邊有塊,就不用搜它向左移的情況,因為左邊的塊向右移會更優。剪這乙個應該就可以。還有總結這幾天做題經驗,一定謹慎使...