[PKUSC2018]主鬥地

暴搜

很是暴力的搜索,以致於我都不相信我能過。c++

方法是:暴力枚舉全部牌型,而後暴力判斷是否可行。spa

暴力枚舉部分:

很是暴力:code

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都去掉了,因此總牌型大量縮減。three

判斷部分:

這裏須要用到一個性質,若是一幅飛機或順子能夠大於另一幅同類型的牌,那麼把他拆開來也能夠大於另一幅牌拆開來。it

判斷部分分兩部分,先暴力搜索搜出哪些牌要被拆出來變成三張牌或四張牌。class

由於雙方的總牌數都不會很大,因此直接搜只會帶一個常數。搜索

這裏要注意,只有當九條可憐出了三張牌或四張牌之後,xx網友才能出三張牌或四張牌,否則九條可憐將沒法出小於xx網友的牌型。方法

最後二者出的三張牌和四張牌數量必須相等,否則會有一副牌沒法有對應的牌。im

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);
}

而後再用貪心的方式判斷最後的散牌是否能夠。while

枚舉有多少的三張牌要帶一個,而後獲得有多少的一張牌和多少的兩張牌能夠被帶掉。

對於九條可憐的牌,去掉最大的牌。對於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);
}
相關文章
相關標籤/搜索