撥鍾問題 OpenJ_Bailian
阿新 • • 發佈:2019-01-26
這是一道和畫家問題,熄燈問題極為相似的題目。
共同特性:操作對環境的改變是無序的,每個操作都會影響到周圍的狀態。
同時每一種操作都有周期性限制,也即最多需要幾次操作,多於這個次數產生相等效果的迴圈。
這類題也有一個共同的解決思路:確定一個小的列舉方案,這個列舉方案產生的結果一定會促使下面的操作。例如本題中我們隨機列舉1,2,3操作,如果A,B,C沒有歸零我們就必須操作4,5,6來讓其歸零(此時只有4,5,6可以影響A,B,C)。最後我們再來操作7,9能否讓D,E,F歸零(此時只有7,9可以影響D,E,F),最後我們再來操作8讓G,H,I歸零,如果可以做到,則記錄下該解。
解決思路有了,前期我來這樣寫的話結果是寫出了一個大模擬,還一直有bug。
在此寫一句話:數學思路是大模擬的剋星
對於很多噁心人的大模擬,其實一般都有數學規律可循,找到了數學規律也就可以避免模擬中的亂七八糟的陣列,n^2複雜度。。
在網上借鑑了一位大神的思路,程式碼如下:
#include<cstdio> int z[10], i[10], sum; //鐘錶,操作和操作步數 int main() { for(int j = 1; j <= 9; j++) scanf("%d", &z[j]); for(i[1] = 0; i[1] < 4; i[1]++) for(i[2] = 0; i[2] < 4; i[2]++) for(i[3] = 0; i[3] < 4; i[3]++) { //列舉操作1,2,3 i[4] = (4 - (z[1] + i[1] + i[2]) % 4) % 4; i[5] = (4 - (z[2] + i[1] + i[2] + i[3]) % 4) % 4; i[6] = (4 - (z[3] + i[2] + i[3]) % 4) % 4; i[7] = (4 - (z[4] + i[1] + i[4] + i[5]) % 4) % 4; i[9] = (4 - (z[6] + i[3] + i[5] + i[6]) % 4) % 4; i[8] = (4 - (z[8] + i[5] + i[7] + i[9]) % 4) % 4; //8要放在最後 sum = 0; sum += (z[1] + i[1] + i[2] + i[4]) % 4; sum += (z[2] + i[1] + i[2] + i[3] + i[5]) % 4; sum += (z[3] + i[2] + i[3] + i[6]) % 4; sum += (z[4] + i[1] + i[4] + i[5] + i[7]) % 4; sum += (z[5] + i[1] + i[3] + i[5] + i[7] + i[9]) % 4; sum += (z[6] + i[3] + i[5] + i[6] + i[9]) % 4; sum += (z[7] + i[4] + i[7] + i[8]) % 4; sum += (z[8] + i[5] + i[7] + i[8] + i[9]) % 4; sum += (z[9] + i[6] + i[8] + i[9]) % 4; if(sum == 0) { for(int j = 1; j <= 9; j++) while(i[j]--) printf("%d ", j); return 0; } } }