hdu4431 Mahjong 枚举搜索。。

来源:互联网 发布:linux系统环境变量设置 编辑:程序博客网 时间:2024/06/08 13:15

japanese麻将什么玩意。。都没有豪华七对。。。

没什么难的 就是枚举搜索了

分三种类型的胡牌

f1是七对 f2是十三幺 f3是普通的胡牌 就先找一对 再找三个三个的

就是一直超时。。在峰峰的指导下加了好多剪枝 注释都标出来了。。这样才过 而且好慢。。


#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <algorithm>#include <vector>#include <map>using namespace std;int cnt[40],res,ans[40];map<string,int>mp;void init(){    mp["1m"]=1; mp["1s"]=11; mp["1p"]=21;    mp["2m"]=2; mp["2s"]=12; mp["2p"]=22;    mp["3m"]=3; mp["3s"]=13; mp["3p"]=23;    mp["4m"]=4; mp["4s"]=14; mp["4p"]=24;    mp["5m"]=5; mp["5s"]=15; mp["5p"]=25;    mp["6m"]=6; mp["6s"]=16; mp["6p"]=26;    mp["7m"]=7; mp["7s"]=17; mp["7p"]=27;    mp["8m"]=8; mp["8s"]=18; mp["8p"]=28;    mp["9m"]=9; mp["9s"]=19; mp["9p"]=29;    mp["1c"]=31;mp["2c"]=32; mp["3c"]=33;    mp["4c"]=34;mp["5c"]=35; mp["6c"]=36;    mp["7c"]=37;}int f1()//7dui{    int a=0;    for(int i=1;i<=38;i++)    {        if(cnt[i]==2) a++;    }    return a==7;}int f2()//13yao{    int i,j;    for(i=0;i<30;i+=10)    {        if(!cnt[i+1]||!cnt[i+9]) return 0;        for(j=2;j<9;j++)            if(cnt[i+j]) return 0;    }    for(i=31;i<=37;i++)        if(!cnt[i]) return 0;    return 1;}int dfs(){    int i;    if(res==0) return 1;    for(i=1;i<30;i++)    {        if(cnt[i]>=3)        {            cnt[i]-=3;            res-=3;            if(dfs()){                cnt[i]+=3;                res+=3;                return 1;            }            cnt[i]+=3;            res+=3;        }    }    for(i=1;i<30;i++)    {        if(cnt[i]&&cnt[i+1]&&cnt[i+2])        {            cnt[i]--;            cnt[i+1]--;            cnt[i+2]--;            res-=3;            if(dfs()){                cnt[i]++;                cnt[i+1]++;                cnt[i+2]++;                res+=3;                return 1;            }            cnt[i]++;            cnt[i+1]++;            cnt[i+2]++;            res+=3;        }    }    return 0;}int f3(){    int i;    for(i=1;i<38;i++)        if(cnt[i]>=2)        {            cnt[i]-=2;            res=12;            int ok=1;//这里再加一个剪枝 先找出连不成一句话的三个一样的            for(int j=31;j<=37;j++)            {                if(cnt[j]==3) res-=3;//减小dfs                else if(cnt[j]) {ok=0;break;}            }            if(!ok) {cnt[i]+=2;continue;}            if(dfs())            {                cnt[i]+=2;                return 1;            }            cnt[i]+=2;        }    return 0;}int main(){    int t,i,k;    char s[5];    init();    scanf("%d",&t);    while(t--)    {        memset(cnt,0,sizeof cnt);        for(i=0;i<13;i++)        {            scanf("%s",s);            cnt[mp[s]]++;        }        for(i=1,k=0;i<=37;i++)        {            if(i%10==0||cnt[i]==4) continue;//如果这张牌已经有四个就不用加啦            cnt[i]++;            if(cnt[i]==4&&!cnt[i-1]&&!cnt[i+1]){                cnt[i]--;//如果这张牌有四个 且相邻两个都没有 那一定不能胡                continue;            }            if(f2()){                ans[k++]=i;                cnt[i]--;                continue;            }            else if(cnt[i]==1&&!cnt[i-1]&&!cnt[i+1]){                cnt[i]--;//判断为不是十三幺后                continue;//如果这张牌只有一个 而且前后都没有 那一定不能胡            }            if(f1()||f3())                ans[k++]=i;            cnt[i]--;        }        if(k)        {           // sort(ans.begin(),ans.end());//mark            printf("%d",k);            for(i=0;i<k;i++)            {                if(ans[i]<10)                    printf(" %dm",ans[i]%10);                else if(ans[i]<20)                    printf(" %ds",ans[i]%10);                else if(ans[i]<30)                    printf(" %dp",ans[i]%10);                else printf(" %dc",ans[i]%10);            }            putchar('\n');        }        else printf("Nooten\n");    }    return 0;}




原创粉丝点击