zoukankan      html  css  js  c++  java
  • 【NOIP】提高组2015 斗地主

    【题意】按照斗地主出牌规则,给定手牌求出完的最少步数。

    【算法】模拟+搜索

    【题解】

     可以发现除了顺子,其它的出牌规则都和点数无关,只与同点数的牌数有关。

     所以可以先暴力枚举要出哪些顺子,然后每一个出完顺子后手牌的情况处理成b[4]表示牌数为1~4的点数有多少个,然后进行dfs。(为了方便,将A接在14,然后注意2不能顺)

     dfs(s,t,j,z)表示有s组牌数为1,有t组牌数为2,有j组牌数为3,有z组牌数为4的情况出完手牌的最少步数。(可以记忆化)

    然后在dfs讨论一下【单打】【拆牌】【带牌】三种情况,对应转移就可以了。(数据小,写多暴力都没关系)

    双王在进入dfs前特殊处理:有双王就考虑多一种当炸弹打的情况,然后就直接将王当作单排进入dfs。

    代码已通过各大OJ增强版(>w<)。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=30,inf=0x3f3f3f3f;
    const int limit[5]={0,5,3,2};
    int f[maxn][maxn][maxn][maxn],a[maxn],b[maxn];
    int min(int a,int b){return a<b?a:b;}
    int dfs(int s,int t,int j,int z){
        if(~f[s][t][j][z])return f[s][t][j][z];
        int ans=inf;
        if(t)ans=min(ans,dfs(s+2,t-1,j,z));
        if(j)ans=min(ans,dfs(s+1,t+1,j-1,z));
        if(z)ans=min(ans,min(dfs(s,t+2,j,z-1),dfs(s+1,t,j+1,z-1)));
        if(j&&s)ans=min(ans,dfs(s-1,t,j-1,z)+1);
        if(j&&t)ans=min(ans,dfs(s,t-1,j-1,z)+1);
        if(z&&s>1)ans=min(ans,dfs(s-2,t,j,z-1)+1);
        if(z&&t>1)ans=min(ans,dfs(s,t-2,j,z-1)+1);
        return f[s][t][j][z]=min(ans,s+t+j+z);
    }
    int calc(int step){
        int ans=inf,tot;
        for(int k=1;k<=3;k++){
            for(int i=3;i<=14;i++){
                tot=0;
                for(int j=i;j<=14;j++)if(a[j]>=k)tot++;else break;
                for(int j=i+limit[k]-1;j<=i+tot-1;j++){
                    for(int l=i;l<=j;l++)a[l]-=k;
                    ans=min(ans,calc(step+1));
                    for(int l=i;l<=j;l++)a[l]+=k;
                }
            }
        }
        b[1]=b[2]=b[3]=b[4]=0;
        for(int i=2;i<=14;i++)b[a[i]]++;
        if(a[0]==2)ans=min(ans,step+1+dfs(b[1],b[2],b[3],b[4]));
        b[1]+=a[0];
        ans=min(ans,step+dfs(b[1],b[2],b[3],b[4]));
        return ans;
    }            
    int main(){
        int T,n;
        scanf("%d%d",&T,&n);
        memset(f,-1,sizeof(f));
        f[0][0][0][0]=0;
        while(T--){
            int u,v;
            memset(a,0,sizeof(a));
            for(int i=1;i<=n;i++){
                 scanf("%d%d",&u,&v);
                 a[u]++;
            }
            a[14]=a[1];
            printf("%d
    ",calc(0));
        }
        return 0;
    }//thanks for Lucius's code!
    View Code
  • 相关阅读:
    Java中的Throwable类是不是受查异常?
    win10下写sh脚本出现^M字符的解决方法
    spring security中Authority、Role的区别
    idea调试框架时如何能够进入maven依赖包的源码
    推荐一个程序员阅读文章资料时的辅助神器
    MySQL添加、修改、撤销用户数据库操作权限的一些记录
    AndroidStudio布局编辑器强制刷新布局界面
    Android Stadio导入Android工程项目,只有Edit Configurations的解决办法
    GitHub克隆下载代码速度慢解决办法
    python各种类型日期转换大全
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7759808.html
Copyright © 2011-2022 走看看