[PKUSC2018]主斗地

暴搜

非常暴力的搜索,以至于我都不相信我能过。

方法是:暴力枚举所有牌型,然后暴力判断是否可行。

暴力枚举部分:

非常暴力:

void dfs(int x,int l){
    if(l==0){
        flag=0;
        check(1,0,0,0,0);
        if(flag)ans++;
        return;
    }
    if(x>14)return;
    for(res i=0;i<=limit[x]&&i<=l;++i){
        jiry[x]=i;
        dfs(x+1,l-i);
    }
}

搜下来发现牌型数量不大于\(3000000\),因为出题人良心的把3都去掉了,所以总牌型大量缩减。

判断部分:

这里需要用到一个性质,如果一幅飞机或顺子可以大于另外一幅同类型的牌,那么把他拆开来也可以大于另外一幅牌拆开来。

判断部分分两部分,先暴力搜索搜出哪些牌要被拆出来变成三张牌或四张牌。

因为双方的总牌数都不会很大,所以直接搜只会带一个常数。

这里要注意,只有当九条可怜出了三张牌或四张牌以后,xx网友才能出三张牌或四张牌,不然九条可怜将无法出小于xx网友的牌型。

最后两者出的三张牌和四张牌数量必须相等,不然会有一副牌无法有对应的牌。

void check(int x,int one,int oneortwo,int three,int four){
    if(x>14){
        if(three||four)return;
        check(one,oneortwo);
        return;
    }
    if(jiry[x]>=4){
        jiry[x]-=4;
        check(x+1,one+1,oneortwo,three,four+1);
        jiry[x]+=4;
        if(flag)return;
    }
    if(jiry[x]>=3){
        jiry[x]-=3;
        check(x+1,one,oneortwo+1,three+1,four);
        jiry[x]+=3;
        if(flag)return;
    }
    if(xx[x]>=4&&four){
        xx[x]-=4;
        check(x+1,one,oneortwo,three,four-1);
        xx[x]+=4;
        if(flag)return;
    }
    if(xx[x]>=3&&three){
        xx[x]-=3;
        check(x+1,one,oneortwo,three-1,four);
        xx[x]+=3;
        if(flag)return;
    }
    check(x+1,one,oneortwo,three,four);
}

然后再用贪心的方式判断最后的散牌是否可以。

枚举有多少的三张牌要带一个,然后得到有多少的一张牌和多少的两张牌可以被带掉。

对于九条可怜的牌,去掉最大的牌。对于xx网友的牌,去掉最小的牌。要先用两张牌来贪心,再用一张牌来贪心。

剩下的牌直接扫一遍,如果在前\(i\)种牌中xx网友的牌比九条可怜的要多,则当前牌错误。

void check(int one,int oneortwo){
    for(res i=0;i<=oneortwo;i++){
        memcpy(jirycpy,jiry,sizeof jiry);
        memcpy(xxcpy,xx,sizeof xx);
        res o=i+one*2,t=oneortwo-i;
        for(res j=1;j<=14;++j){
            while(xxcpy[j]>=2&&t)xxcpy[j]-=2,t--;
            while(xxcpy[j]>=1&&o)xxcpy[j]-=1,o--;
        }
        if(o||t)continue;
        o=i+one,t=oneortwo-i;
        for(res j=14;j;--j){
            while(jirycpy[j]>=2&&t)jirycpy[j]-=2,t--;
            while(jirycpy[j]>=1&&o)jirycpy[j]-=1,o--;
        }
        if(o||t)continue;
        flag=1;
        for(res j=1,now=0;j<=14;++j){
            now-=xxcpy[j];
            if(now<0){
                flag=0;
                break;
            }
            now+=jirycpy[j];
        }
        if(flag)return;
    }
}

然后是完整代码

#include<bits/stdc++.h>
#define res register int
using namespace std;
char str[15];
int jiry[15],xx[15],limit[15];
int jirycpy[15],xxcpy[15];
int cl(char c){
    if(c=='T')return 7;
    else if(c=='J')return 8;
    else if(c=='Q')return 9;
    else if(c=='K')return 10;
    else if(c=='A')return 11;
    else if(c=='2')return 12;
    else if(c=='w')return 13;
    else if(c=='W')return 14;
    else return c-'3';  
}
bool flag;
int ans;
void check(int one,int oneortwo){
    for(res i=0;i<=oneortwo;i++){
        memcpy(jirycpy,jiry,sizeof jiry);
        memcpy(xxcpy,xx,sizeof xx);
        res o=i+one*2,t=oneortwo-i;
        for(res j=1;j<=14;++j){
            while(xxcpy[j]>=2&&t)xxcpy[j]-=2,t--;
            while(xxcpy[j]>=1&&o)xxcpy[j]-=1,o--;
        }
        if(o||t)continue;
        o=i+one,t=oneortwo-i;
        for(res j=14;j;--j){
            while(jirycpy[j]>=2&&t)jirycpy[j]-=2,t--;
            while(jirycpy[j]>=1&&o)jirycpy[j]-=1,o--;
        }
        if(o||t)continue;
        flag=1;
        for(res j=1,now=0;j<=14;++j){
            now-=xxcpy[j];
            if(now<0){
                flag=0;
                break;
            }
            now+=jirycpy[j];
        }
        if(flag)return;
    }
}
void check(int x,int one,int oneortwo,int three,int four){
    if(x>14){
        if(three||four)return;
        check(one,oneortwo);
        return;
    }
    if(jiry[x]>=4){
        jiry[x]-=4;
        check(x+1,one+1,oneortwo,three,four+1);
        jiry[x]+=4;
        if(flag)return;
    }
    if(jiry[x]>=3){
        jiry[x]-=3;
        check(x+1,one,oneortwo+1,three+1,four);
        jiry[x]+=3;
        if(flag)return;
    }
    if(xx[x]>=4&&four){
        xx[x]-=4;
        check(x+1,one,oneortwo,three,four-1);
        xx[x]+=4;
        if(flag)return;
    }
    if(xx[x]>=3&&three){
        xx[x]-=3;
        check(x+1,one,oneortwo,three-1,four);
        xx[x]+=3;
        if(flag)return;
    }
    check(x+1,one,oneortwo,three,four);
};
void dfs(int x,int l){
    if(l==0){
        flag=0;
        check(1,0,0,0,0);
        if(flag)ans++;
        return;
    }
    if(x>14)return;
    for(res i=0;i<=limit[x]&&i<=l;++i){
        jiry[x]=i;
        dfs(x+1,l-i);
    }
}
int main(){
    scanf("%s",str+1);
    int len=strlen(str+1);
    for(int i=1;i<=12;++i){
    	limit[i]=4;
    }
    limit[13]=limit[14]=1;
    memset(xx,0,sizeof xx);
    for(int i=1;i<=len;++i){
        limit[cl(str[i])]--;
        xx[cl(str[i])]++;
    }
    ans=0;
    dfs(1,17); 
    printf("%d\n",ans);
}
posted @ 2019-05-23 09:46  整理者  阅读(603)  评论(0编辑  收藏  举报