傳送門
考場上的思路
什麼叫做最優策略???我暴力都打不來怎麼辦???好像 n,
m=2 n,m
=2
可以直接得出答案,m=
1 m=1
也可以直接算,就這樣有了
25 25
分。但是不能坐以待斃啊!觀察了一下 n,
m=2 n,m
=2
是怎麼算的,發現需要做一次決策,且這次決策由後手決定。乖乖,還是寫個 dp 吧……設 fb
nbn−
1⋯b1
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯(m
+1) fbn
bn−1
⋯b1¯
(m+1
)表示第
j j
行選了前 bj
' role="presentation" style="position: relative;">bjb
j個時(不難發現選了的呈階梯狀)的答案。邊界條件為 f0
=0f 0=
0,最終答案為 fm
m⋯m¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
(m+1
) fmm
⋯m¯(
m+1)
。乖乖,怎麼轉移的?如果當前該先手走,想要走出差距最大的分,那就取
max max
吧。乖乖,樣例都過不了……一想,既然對手絕頂聰明,那肯定當前的決策只能最差啊(不知道我是怎麼想的),那就取
min min
吧。一看樣例過了(我無法手算資料),我就走了。最後果然多得了
5 5
分……正解正確思路也是 dp,只不過它的最優策略是這個意思:在接下來的決策中會走出最優策略(仔細感悟下這個 dp)。
於是我們重新設一下狀態。設 fb
nbn−
1⋯b1
¯(m+
1)' role="presentation" style="position: relative;">fbn
bn−1
⋯b1¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯(m+
1)fb
nbn−
1⋯b1
¯(m+
1)表示第
j j
行選了前 bj
' role="presentation" style="position: relative;">bjb
j個時接下來選出的最大值(如果這次該先手走)或者最小值(如果這次該後手走)(這裡指兩人分數的差的最大或者最小值)。如果該先手走,自然就要取
max max
了,如果該後手走,自然就要取
min min
了。最後答案為 f0
f
0,邊界為 fm
m⋯m¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
¯¯¯¯
(m+1
)=0 fmm
⋯m¯(
m+1)
=0
。這樣做就有
80 80
分了。仔細觀察發現,雖然我們用乙個 m+
1 m+1
進製數來表示狀態,但是狀態總數其實很少(因為必須呈階梯狀)。有多少呢?這個階梯狀不就是矩陣中從乙個端點走到另乙個端點嗎?有 c10
20 c
2010
種狀態,也就是說時間是絕對可以過的,只是空間好像需要更好的方法。
乙個很好的解決方法是輪廓線。我們把階梯狀橫著走看成
0 0
,豎著走看成
1' role="presentation" style="position: relative;">1
1,則乙個狀態可以用乙個
20 20
位的二進位制數表示,這就可以過了。
時間複雜度 o(
ncmn
+m) o(n
cn+m
m)
,空間複雜度 o(
2n+m
) o(2
n+m)
。參考**
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef
long
long ll;
typedef
unsigned
long
long ull;
using
std::cin;
using
std::cout;
using
std::endl;
typedef
int int_put;
int_put readin()
while (std::isdigit(ch))
return positive ? -a : a;
}void printout(int_put x)
const
int maxn = 12;
int n, m;
int a[maxn][maxn];
int b[maxn][maxn];
#define runinstance(x) delete new x
struct cheat1
};struct cheat2
};struct brute1
int calchash(int bit[maxn])
ret = ret << 1 | 1;
}while (cnt <= bit[0])
return ret;
}ll u;
int dp(ll s)
;ll t = s;
int sum = 0;
for (int i = 1; i <= n; i++)
int& ans = f[calchash(bit)];
if (ans != -1) return ans;
if (s == u - 1)
return ans = 0;
if (!(sum & 1)) // a 操作}}
else
// b 操作}}
return ans;
}brute1()
};void run()
int main()
總結
這個題 dp 要倒著做應該還是比較明顯的,但是考場上卻忘了這一茬。
使用輪廓線表示這種階梯狀態是個很不錯的選擇。
一雙木棋(chess)
題目描述 菲菲和牛牛在一塊 nn 行 mm 列的棋盤上下棋,菲菲執黑棋先手,牛牛執白棋后手。棋局開始時,棋盤上沒有任何棋子,兩人輪流在格仔上落子,直到填滿棋盤時結束。落子的規則是 乙個格仔可以落子當且僅當這個格仔內沒有棋子且這個格仔的左側及上方的所有格仔內都有棋子。棋盤的每個格仔上,都寫有兩個非負整...
九省聯考2018 一雙木棋
我們容易知道,棋子的擺放形狀應該是乙個階梯性 某dalao 來來來,輪廓線dp!我們選擇用狀態壓縮來表示整個棋盤的排放形態 11進製壓位,每個位上的數都表示一行的狀態 這樣子我們每次對合法狀態進行拓展,dfs搜尋下去。輪到菲菲,我們期望她的得分大一些,而到牛牛,我們期望她的得分少一些。所以我們對前者...
BZOJ5248 一雙木棋(Min Max搜尋)
題面 不顯然,能下棋的地方對於每一行是非嚴格遞減的 可以用乙個n 1進製數來表示這個輪廓線 狀態數就是n個球放m 1個盒子裡的方案數,不會太大 然後就是大佬們所說的對抗搜尋 include include include include include include include include...