牌局 By liuzhangfeiabc - 模拟 - 搜索

模拟搜索真刺激
z_y_b 他真无敌
(又押韵了啊QwQ)
题目大意:
唔……直接粘原来的题目大意好了:

游戏中共有7种宝石,分别是红色(R),橙色(O),黄色(Y),绿色(G),蓝色(B),紫色(P)和白色(W)。

一副手牌由5张牌组成,在比较得分时,会先根据牌型特点进行分类,类别高的牌得分更高;在等级相同时,则会根据颜色的不同进一步判断。

手牌分类的依据如下:

编号 名称 特征 内部比较方式 举例

1 一对 恰好有2张牌颜色相同 先比较对子的颜色,相同时比较单张最大的颜色,再相同时比较单张次大的颜色,以此类推 RRWGB,WBGOB……

2 顺子 所有牌颜色均不同 先比较最大的颜色,相同时比较次大的颜色,以此类推 BWGOY,YGPWR……

3 两对 恰好有2对牌颜色相同 先比较较大的一对的颜色,相同时比较较小的一对的颜色,再相同时比较单张的颜色 OGBOB,RRPPW……

4 三条 恰好有3张牌颜色相同 先比较三张相同的颜色大小,相同时比较单张中较大的一张,再相同时比较单张中较小的一张 PWWOW,BBBYR……

5 葫芦 3张牌颜色相同,另外2张牌颜色相同 先比较相同的3张,相同时比较剩余2张 BBGGB,PRRRP……

6 四条 恰好4张牌颜色相同 先比较相同的4张,相同时再比较剩余的单张 YYYYO,RRWRR……

7 同花 所有牌颜色相同 比较颜色大小 BBBBB,PPPPP……

(额你问我为什么一对比顺子小?我也不知道啊游戏就是这么设定的qwq)

颜色的大小顺序是按照字母的字典序排序的,即B<G<O<P<R<W<Y。

手牌的顺序对于大小没有影响,当且仅当两副手牌按字典序排序后完全相同时,这两副手牌的得分相同。

这个游戏的界面是一个n行m列的棋盘,行数从上到下,列数从左到右依次增大,每个格子里有一个某种颜色的宝石。

另外,本题中还会提供长度为k的备用条,供宝石消除后补充用。

每次操作的规则如下:

1、选择一个格子中的宝石,将其颜色作为当前牌的颜色。

2、将这个宝石与上下左右某一方向的宝石交换。注意不能交换到棋盘外。

3、当且仅当能够消除原先选定的宝石时,本次操作是合法的。

消除的规则是:当一行或一列上有连续3个或更多颜色相同的宝石时,这些宝石将会被消除。注意一次移动可能会消除不止一处的宝石。

4、消除后,所有上方的宝石将会遵循重力下落(注意宝石位于的行数实际上会增大)。

5、此时棋盘上方出现了空格,将根据以下规则进行填充:

按照从左到右,从下到上,按列填充的顺序,依次从备用条中取出当前最前方的宝石填充进去。如果备用条已用完,将从开头处循环使用。

6、填充完毕后,如果依然存在可以消除的现象,将会继续消除、下落、填充,直至某次填充完毕后不存在可以继续消除的现象为止。

对于游戏中的其他特殊属性,本题目不再考虑。

某天,ldlsn发现这个游戏很好玩,于是向liuzhangfeiabc发起挑战:

两人将面对n,m,k相同的两个棋盘,每人操作5次,获得一副手牌,以手牌大小决胜负。

对于前10%的数据,只含有不超过3种颜色。

对于前20%的数据,只含有不超过4种颜色。

对于前40%的数据,只含有不超过5种颜色。

对于前60%的数据,只含有不超过6种颜色。

对于前30%的数据,n,m<=4。

对于前60%的数据,n,m<=6。

对于100%的数据,1<=n,m<=8,1<=T<=5,1<=k<=100。

数据保证:

1、初始局面不存在可以直接消除的现象;

2、对于玩家的任意合法决策,不存在陷入死循环等无法终局的情况。

3、可能存在这样的局面:对于玩家的任意合法决策,均无法实现5次操作。此时认为玩家的手牌分数最低,当两人均如此时仍视为平局。
当两人的决策均为最优时,谁能最终取胜?

题解

然后我写了个Score类和Player类。
Score类用于计算一副手牌的权值(是一个pair<int,int>类型)。
Player类用于模拟棋盘。
加了一个剪枝是如果当前手牌不可能比当前答案大,就退出。
现在想想其实还应该写一个Board类,然后用Player类合并起来。
总之代码大概两百行,5个k左右的样子(其实还挺好写的):

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
const int maxKind=7,terms=5;
inline int toi(char c)
{
    switch(c)
    {
        case 'B':case 'b':return 1;
        case 'G':case 'g':return 2;
        case 'O':case 'o':return 3;
        case 'p':case 'P':return 4;
        case 'R':case 'r':return 5;
        case 'W':case 'w':return 6;
        case 'Y':case 'y':return 7;
        default:assert(0);
    }
    return 0;
}
struct Score{
    pii value;int cnt[10];
    Score() {}
    Score(int *a) { init(a); }
    inline void init(int *a)
    {
        memset(cnt,0,sizeof(int)*(maxKind+1));
        rep(i,1,terms) cnt[a[i]]++;int mx=0,x=0;
        rep(i,1,maxKind) if(mx<cnt[i]) mx=cnt[i],x=i;
        if(mx==5) { value=mp(7,x);return; }
        if(mx==4) 
        {
            value.fir=6,value.sec=x*10;
            rep(i,1,maxKind) if(cnt[i]==1) value.sec+=i;
            return;
        }
        if(mx==3)
        {
            value.fir=4,value.sec=0;
            for(int i=1,t=1;i<=maxKind;i++)
                if(cnt[i]==2) { value.fir=5,value.sec=x*10+i;return; }
                else if(cnt[i]==1) value.sec+=i*t,t*=10;
            value.sec+=x*100;return;
        }
        if(mx==1)
        {
            for(int i=1,t=1;i<=maxKind;i++)
                if(cnt[i]) value.sec+=i*t,t*=10;
            value.fir=2;return;
        }
        assert(mx==2);int t=0;
        rep(i,1,maxKind) if(cnt[i]==2) t++;
        if(t==1)
        {
            value.fir=1,value.sec=x*1000;
            for(int i=1,t=1;i<=maxKind;i++)
                if(cnt[i]==1) value.sec+=i*t,t*=10;
            return;
        }
        value.fir=3,value.sec=0;
        for(int i=1,t=10;i<=maxKind;i++)
            if(cnt[i]==2) value.sec+=i*t,t*=10;
            else if(cnt[i]) assert(cnt[i]==1),value.sec+=i;
    }
    inline bool operator<(const Score &s)const { return this->value<s.value; }
    inline bool operator>(const Score &s)const { return this->value>s.value; }
    inline bool operator==(const Score &s)const { return this->value==s.value; }
    inline bool operator<=(const Score &s)const { return this->value<=s.value; }
    inline bool operator>=(const Score &s)const { return this->value>=s.value; }
    inline void show()const
    {
        cerr<<value.fir<<" "<<value.sec<<endl;
    }
};
inline Score best_score(int *a,int len)
{
    static int cnt[10],b[10];
    memset(cnt,0,sizeof(int)*(maxKind+1));
    rep(i,1,len) cnt[a[i]]++;int mx=0,x=0;
    rep(i,1,maxKind) if(mx<=cnt[i]) mx=cnt[i],x=i;
    rep(i,len+1,terms) cnt[x]++;int c=0;
    rep(i,1,maxKind) rep(j,1,cnt[i]) b[++c]=i;
    return Score(b);
}
int dx[10]={1,0,-1,0},dy[10]={0,-1,0,1};
struct Player{
    static int n,m,k;int sav[10][20][20],top,a[10],bytsav[10],bytp;
    char str[200];int b[20][20],del[20][20],byt[200];
    Score score;Player():top(0){}
    inline void save()
    {
        top++;
        bytsav[top]=bytp;
        rep(i,1,n) rep(j,1,m) sav[top][i][j]=b[i][j];
    }
    inline void back()
    {
        assert(top);
        rep(i,1,n) rep(j,1,m) b[i][j]=sav[top][i][j];
        bytp=bytsav[top];
        top--;
    }
    inline void input()
    {
        rep(i,1,n)
        {
            scanf("%s",str+1);
            rep(j,1,m) b[i][j]=toi(str[j]);
        }
        scanf("%s",str+1);
        rep(i,1,k) byt[i]=toi(str[i]);
    }
    inline int next_byt()
    {
        bytp++;
        if(bytp>k) bytp=1;
        return byt[bytp];
    }
    inline bool can(int x,int y)
    {
        if(x-2>=1&&b[x][y]==b[x-1][y]&&b[x][y]==b[x-2][y]) return 1;
        if(x+2<=n&&b[x][y]==b[x+1][y]&&b[x][y]==b[x+2][y]) return 1;
        if(y-2>=1&&b[x][y]==b[x][y-1]&&b[x][y]==b[x][y-2]) return 1;
        if(y+2<=m&&b[x][y]==b[x][y+1]&&b[x][y]==b[x][y+2]) return 1;
        if(x-1>=1&&x+1<=n&&b[x][y]==b[x-1][y]&&b[x][y]==b[x+1][y]) return 1;
        if(y-1>=1&&y+1<=m&&b[x][y]==b[x][y-1]&&b[x][y]==b[x][y+1]) return 1;
        return 0;
    }
    inline bool Clear()
    {
        rep(i,1,n) rep(j,1,m) del[i][j]=0;bool ok=false;
        rep(i,1,n) rep(j,1,m)
        {
            if(i+2<=n&&b[i][j]==b[i+1][j]&&b[i][j]==b[i+2][j]) del[i][j]=del[i+1][j]=del[i+2][j]=1;
            if(j+2<=m&&b[i][j]==b[i][j+1]&&b[i][j]==b[i][j+2]) del[i][j]=del[i][j+1]=del[i][j+2]=1;
            if(del[i][j]) ok=true;
        }
        return ok;
    }
    inline void Fall()
    {
        rep(j,1,m)
        {
            int t=n+1;
            for(int i=n;i;i--)
                if(del[i][j]) continue;
                else b[--t][j]=b[i][j];
            for(t--;t;t--) b[t][j]=next_byt();
        }
    }
    inline void maintain()
    {
        while(Clear()) Fall();
    }
    inline bool canSwap(int x,int y,int s,int t)
    {
        swap(b[x][y],b[s][t]);
        int ok=can(s,t);
        swap(b[x][y],b[s][t]);
        return ok;
    }
    inline void Swap(int x,int y,int s,int t)
    {
        swap(b[x][y],b[s][t]);
    }
    void dfs(int curTerms)
    {
        if(best_score(a,curTerms-1)<=score) return;
        if(curTerms==terms+1) { score=max(score,Score(a));return; }
        rep(i,1,n) rep(j,1,m) rep(d,0,3)
        {
            int x=i+dx[d],y=j+dy[d];
            if(x<1||x>n||y<1||y>m||b[x][y]==b[i][j]) continue;
            if(!canSwap(i,j,x,y)) continue;
            a[curTerms]=b[i][j];
            save();
            Swap(i,j,x,y);
            maintain();
            dfs(curTerms+1);
            back();
        }
        return;
    }
    inline void get_score()
    {
        score.value=mp(-1,0);
        top=0;
        bytp=0;
        dfs(1);
    }
    inline void show()
    {
        debug(n)sp,debug(m)sp,debug(k)ln;
        rep(i,1,k) cerr<<byt[i];cerr ln ln;
        rep(i,1,n) { rep(j,1,m) cerr<<b[i][j];cerr ln; }
        debug(bytp)ln ln;
        debug(top)ln ln;
        rep(i,1,top)
        {
            debug(i)ln;
            rep(j,1,n) { rep(k,1,m) cerr<<sav[i][j][k];cerr ln; }
            debug(bytsav[i])ln ln;
        }
    }
}p1,p2;
int Player::n=0,Player::m=0,Player::k=0;
int main()
{
    int T;cin>>T;
    while(T--)
    {
        cin>>Player::n>>Player::m>>Player::k;
        p1.input(),p2.input();
        p1.get_score(),p2.get_score();
        if(p1.score==p2.score) printf("draw\n");
        else if(p1.score>p2.score) printf("liuzhangfeiabc\n");
        else printf("ldlsn\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值