bzoj5248 [2018多省省队联测]一双木棋
Description
菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。棋局开始时,棋盘上没有任何棋子,
两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且
这个格子的左侧及上方的所有格子内都有棋子。
棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij、Bij。在
游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所
有有白棋的格子上的Bij的和。
菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都
采用最优策略且知道对方会采用最优策略,那么,最终的结果如何
Input
第一行包含两个正整数n,m,保证n,m≤10。
接下来n行,每行m个非负整数,按从上到下从左到右的顺序描述每个格子上的
第一个非负整数:其中第i行中第j个数表示Aij。
接下来n行,每行m个非负整数,按从上到下从左到右的顺序描述每个格子上的
第二个非负整数:其中第i行中第j个数表示Bij
n, m ≤ 10 , Aij, Bij ≤ 100000
Output
输出一个整数,表示菲菲的得分减去牛牛的得分的结果。
Sample Input
2 3
2 7 3
9 1 2
3 7 2
2 3 1
2 7 3
9 1 2
3 7 2
2 3 1
Sample Output
2
考虑到n,m都很小
所以我们可以维护轮廓线
一开始我有一个naive的想法
f[s]表示轮廓线状态为s时能取得的最优解,当前为先手取的话取max,后收取的话取min
但是我发现这么做好像不对
想了想改成f[s]表示轮廓线状态为s时能取得的最优解,当前为先手取的话取min,后收取的话取max
发现还是不对
这样做不能决定是谁的最优
所以定义f[s]为状态为s时最多/最少还能得到的多少分数
然后就可以瞎**dp了
//%std #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<stack> #include<set> #include<map> using namespace std; #define lovelive long long #define lc son[x][0] #define rc son[x][1] #define lowbit(x) (x&(-x)) #define pt vc void read(int &x) { int p=1; x=0; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') p=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-48; c=getchar(); } x*=p; } map<lovelive,int> sp; int f[200020]; lovelive a[200020],tot; int A[2][11][11],n,m; void dfs(int i,lovelive j,lovelive lim,lovelive pre) { if(i==n) { pre=pre*lim+j; a[++tot]=pre; sp[pre]=tot; return; } for(int k=0;k<=j;k++) dfs(i+1,j-k,lim,pre*lim+k); } lovelive pw[20]; bool calc(lovelive x) { int sum=m; int now=0; for(int j=0;j<n;j++) { sum-=x%(m+1); now^=sum; x/=(m+1); } return now&1; } int main() { // freopen("chess.in","r",stdin); // freopen("chess.out","w",stdout); int now=0,sum; lovelive x,y,tmp; read(n);read(m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(A[0][i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(A[1][i][j]),A[1][i][j]*=-1; pw[0]=1; for(int i=1;i<=n;i++) pw[i]=pw[i-1]*(lovelive)(m+1); dfs(0,m,m+1,0); for(int i=1;i<=tot;i++) { if(!calc(a[i])) f[i]=-1e9; else f[i]=1e9; } f[1]=0; for(int i=1;i<=tot;i++) { // if(f[i]!=0) // i--,i++; x=y=a[i]; now=calc(a[i]); sum=m; for(int j=0;j<n;j++) { sum-=x%(m+1); // if(y-pw[j]+pw[j+1]==23579400) // i--,i++; if(x%(m+1)!=0) { if(now) f[sp[y-pw[j]+pw[j+1]]]=max(f[sp[y-pw[j]+pw[j+1]]],f[i]+A[now][j+1][sum+1]); else f[sp[y-pw[j]+pw[j+1]]]=min(f[sp[y-pw[j]+pw[j+1]]],f[i]+A[now][j+1][sum+1]); } x/=(m+1); } } cout<<f[sp[m*pw[n]]]<<"\n"; return 0; } /* 2 3 2 7 3 9 1 2 3 7 2 2 3 1 10 10 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 */