P4363 [九省聯考2018]一雙木棋chess 狀壓DP
阿新 • • 發佈:2020-12-26
題面:
分析:
- 暴力:
暴搜出每種狀態下每個人的最優決策,期望得分:\(30pts\)
- 正解
我們通過模擬可以發現,最終選擇出來的狀態一定是呈現出梯形的樣子,所以我們聯想到針對形狀的 輪廓線DP,我們規定橫邊用 \(0\) 表示,豎邊用 \(1\) 表示,每一個狀態從右上到左下可表示為一組長度為 \(n+m-2\) 的 \(01\) 序列
序列的初始值是 \(0\dots(m-1個)\ 1\dots(n-1個)\),結束值是 \(1\dots(n-1個)\ 0\dots(m-1個)\)
每一次狀態轉移相當於把一對 \(01\to10\)
複雜度是 \(O(2^{n+m-2}\log)\)
- 另解
對於一人求局面最小值,一人求局面最大值,典型的 \(min-max\) 搜尋,但是單純的 \(min-max\) 搜尋複雜度不對,需要進行 \(\alpha-\beta\) 剪枝 (日後再填坑吧)
程式碼:
#include<bits/stdc++.h> using namespace std; namespace zzc { int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } const int maxn = 10; const int maxm = (1<<(maxn<<1)); const int inf = 1e9+7; bool vis[maxm]; int f[maxm],a[maxn][maxn],b[maxn][maxn]; int n,m; int dfs(int st,int who) { if(vis[st]) return f[st]; f[st]=who?-inf:inf; int x=n,y=0; for(int i=0;i<n+m-1;i++) { if((st>>i)&1) x--; else y++; if((st>>i&3)!=1) continue; int to=st^(3<<i); if(who) f[st]=max(f[st],dfs(to,who^1)+a[x][y]); else f[st]=min(f[st],dfs(to,who^1)-b[x][y]); } vis[st]=true; return f[st]; } void work() { n=read();m=read(); for(int i=0;i<n;i++) for(int j=0;j<m;j++) a[i][j]=read(); for(int i=0;i<n;i++) for(int j=0;j<m;j++) b[i][j]=read(); f[((1<<n)-1)<<m]=0; vis[((1<<n)-1)<<m]=true; printf("%d\n",dfs((1<<n)-1,1)); } } int main() { zzc::work(); return 0; }