題目描述
dd 和 mm 正在玩取石子遊戲。他們的遊戲規則是這樣的:桌上有若干石子,dd 先取,輪流取,每次必須取質數個。如果某一時刻某一方無法從桌上的石子中取質數個,比如說剩下 0 個或 1 個石子,那麼他/她就輸了。
dd 和 mm 都很聰明,不管哪方存在乙個可以必勝的最優策略,他/她都會按照最優策略保證勝利。於是,dd 想知道,對於給定的桌面上的石子數,他究竟能不能取得勝利呢?
當 dd 確定會取得勝利時,他會說:「不管 mm 選擇怎樣的取石子策略,我都能保證至多 x 步以後就能取得勝利。」那麼,最小的滿足要求的 x 是多少呢?注意,不管是 dd 取一次石子還是 mm 取一次石子都應該被計算為「一步」。
輸入格式
第一行有乙個整數 n,表示這個輸入檔案中包含 n 個測試資料。
第二行開始,每行有乙個測試資料,其中僅包含乙個整數,表示桌面上的石子數。
輸出格式
你需要對於每個輸入檔案中的 n 個測試資料輸出相應的 n 行。
如果對於該種情形是 dd 一定取得勝利,那麼輸出最小的 x。否則該行輸出 -1。
樣例輸入
3 8 9 16
樣例輸出
1 -1 3
這是一道簡單的動態規劃(對我來說比較困難)。
看到題目,不難想到列舉最後一次取石子,但是若直接以剩下的石子數作為狀態,就會有後效性,因為最後一次是dd還是mm取石子的轉移條件是不一樣的。
所以考慮將最後一次取石子的人也作為狀態。
定義狀態如下:
用f[i][0]表示剩下i個石子,dd先取,他是否能夠取勝(若能取勝則值為取勝的最小步數,否則為-1。);用f[i][1]表示剩下i個石子,mm先取,dd是否能夠取勝。
轉移方程:f[i][0] = max(f[i - p][1])(所有的f[i - p][1]都不為-1,否則f[i][0] = -1);
f[i][1] = min(f[i - p][0])(有乙個f[i - p][0]不為-1,否則f[i][0] = -1)。
其中,p為所列舉的質數。
提交了4次:
第一次0分;
第二次20分;
第三次20分;之前的錯在在轉移時沒有按先取石子的人進行分類討論。
第四次100分。
accode:
#include #include #include #include const char fi = "rqnoj116.in";
const char fo = "rqnoj116.out";
const int maxn = 50010;
const int maxp = 5000;
const int max = 0x3fffff00;
const int min = -max;
int prime[maxp];
int f[maxn][2];
int n, n;
void init_file()
void mkprime()
}prime[i] = tmp;
f[prime[i]][0] = f[prime[i] + 1][0] = 1;
//在一步以內肯定能成功。
f[prime[i]][1] = f[prime[i] + 1][1] = -1;
//肯定失敗。
}}
void dp(int i, bool odd)
f[i][odd] = std::max(f[i][odd],
f[i - prime[j]][!odd] + 1);
}if (f[i][odd] < -2)
f[i][odd] = -1;
}else
if (f[i][odd] == max)
f[i][odd] = -1;
}}
void work()
}int main()
質數取石子
dd 和 mm 正在玩取石子遊戲。他們的遊戲規則是這樣的 桌上有若干石子,dd 先取,輪流取,每次必須取質數個。如果某一時刻某一方無法從桌上的石子中取質數個,比如說剩下 0 個或 1 個石子,那麼他 她就輸了。dd 和 mm 都很聰明,不管哪方存在乙個可以必勝的最優策略,他 她都會按照最優策略保證勝...
質數取石子
dd 和 mm 正在玩取石子遊戲。他們的遊戲規則是這樣的 桌上有若干石子,dd 先取,輪流取,每次必須取質數個。如果某一時刻某一方無法從桌上的石子中取質數個,比如說剩下 0 個或 1 個石子,那麼他 她就輸了。dd 和 mm 都很聰明,不管哪方存在乙個可以必勝的最優策略,他 她都會按照最優策略保證勝...
動態規劃 石子合併
題目描述 在乙個圓形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入輸出格式 輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石...