zoukankan      html  css  js  c++  java
  • [luogu]P4363 [九省联考2018]一双木棋chess

    [luogu]P4363 [九省联考2018]一双木棋chess

    题目描述

    菲菲和牛牛在一块n 行m 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。

    落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。

    棋盘的每个格子上,都写有两个非负整数,从上到下第i 行中从左到右第j 列的格 子上的两个整数记作(A_{i,j})​ 、(B_{i,j})​。在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的(A_{i,j})​ 之和,牛牛的得分是所有有白棋的格子上的(B_{i,j})​的和。

    菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何。

    输入输出格式

    输入格式:

    从文件chess.in 中读入数据。

    输入第一行包含两个正整数n;m,保证n;m <= 10。

    接下来n 行,每行m 个非负整数,按从上到下从左到右的顺序描述每个格子上的 第一个非负整数:其中第i 行中第j 个数表示(A_{i,j})​。

    接下来n 行,每行m 个非负整数,按从上到下从左到右的顺序描述每个格子上的 第二个非负整数:其中第i 行中第j 个数表示(B_{i,j})

    输出格式:

    输出到文件chess.out 中。

    输出一个整数,表示菲菲的得分减去牛牛的得分的结果。

    输入输出样例

    输入样例#1: 复制

    2 3
    2 7 3
    9 1 2
    3 7 2
    2 3 1

    输出样例#1: 复制

    2

    说明

    样例1说明:

    棋盘如图所示,双方都采用最优策略时,棋局如下:

    • 菲菲下在第1 行第1 列(这是第一步时唯一可以落子的格子);

    • 牛牛下在第1 行第2 列;

    • 菲菲下在第2 行第1 列;

    • 牛牛下在第1 行第3 列;

    • 菲菲下在第2 行第2 列;

    • 牛牛下在第2 行第3 列(这是这一步时唯一可以落子的格子);

    • 填满棋盘,游戏结束,盘面如下。

    菲菲的得分为:2 + 9 + 1 = 12 ;牛牛的得分为:7 + 2 + 1 = 10 。

    对于所有的测试数据,n;m <= 10 ,A_{i,j}Ai,j​; B_{i,j}Bi,j​ <= 100000。

    对于编号为奇数的测试点,保证所有的B_{i,j}Bi,j​ = 0 。

    题解

    听说状态量很少,可以hash一下当前图的轮廓做一下。
    对于博弈来说为了使当前差值最小,可以使用min-max剪枝。
    然后这道题就做完了?反正考场上我是一定写不出来了。

    Code

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<map>
    #define ll long long
    using namespace std;
    map<ll,ll>mp;
    const ll base=13;
    const ll N=15;
    const ll inf=1e9;
    ll n,m,a[N][N],b[N][N],c[N];
    ll read(){
        ll x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    ll Hash(){ll ans=1;for(ll i=1;i<=n;i++)ans=ans*base+c[i];return ans;}
    void unHash(ll x){for(ll i=n;i>=1;i--){c[i]=x%base,x/=base;}}
    
    ll dfs(ll now,ll f){
        if(mp.count(now))return mp[now];
        unHash(now);ll ans=f?-inf:inf;
        for(ll i=1;i<=n;i++){
            if(c[i]<c[i-1]){
                ++c[i];ll tmp=Hash();
                if(f)ans=max(ans,dfs(tmp,0)+a[i][c[i]]);
                else ans=min(ans,dfs(tmp,1)-b[i][c[i]]);
                --c[i];
            }
        }mp[now]=ans;
        return ans;
    }
    
    int main(){
        n=read();m=read();
        for(ll i=1;i<=n;i++)for(ll j=1;j<=m;j++)a[i][j]=read();
        for(ll i=1;i<=n;i++)for(ll j=1;j<=m;j++)b[i][j]=read();
        for(ll i=0;i<=n;i++)c[i]=m;
        mp[Hash()]=0;dfs(0,1);
        cout<<mp[0]<<endl;
        return 0;
    }
    
  • 相关阅读:
    索引!
    事件event
    Erlang运行时源码分析之——线程进度机制
    Erlang 运行时中使用的读写锁解析
    经典互斥算法解析
    网格布局之grid
    注册简单表单
    前端入门之自我介绍
    Python之一后置固件yield和终结函数addfinalizer
    python中yield 与 return 区别
  • 原文地址:https://www.cnblogs.com/hhh1109/p/10532651.html
Copyright © 2011-2022 走看看