枚举+搜索 hdu-4431-Mahjong

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4431

题目大意:

给一副牌,求出所有能糊的牌。

解题思路:

枚举每一张牌,看能不能糊。

因为一共只有14张牌,每次依据将,去掉三张牌,判断最后两张牌是否一样。

七对和十三幺单独考虑,

注意:

1、1p 1p 1s 9s 1m 9m 1c 2c 3c 4c 5c 6c 7c 这样的也可以糊9p。

2、七对时,要为不同的牌,1s 1s 1s 1s 不能糊七对。

剪枝:

1、对于不是c色牌,能糊的牌一定出现在手牌或+1,-1同色牌中,所以只用枚举这些可以糊的牌即可。

2、对于单独的一张牌,左右相邻没有同色牌时,不能糊。

贴几组测试数据:

20
1p 2p 3p 7p 8p 9p 1s 2s 3s 1c 1c 2c 2c
2 1c 2c
1p 2p 3p 3p 3p 3p 4p 5p 1m 2m 3m 4m 5m
2 3m 6m
1s 2s 3s 2c 2c 2c 2p 3p 5m 6m 7m 1p 1p
2 1p 4p
1p 1p 2p 3p 4s 5s 6s 7c 7c 3s 3s 2m 2m
Nooten
1p 1p 1p 2p 2p 3p 3p 4p 4p 5p 6p 7p 8p
6 2p 3p 5p 6p 8p 9p
1p 2p 3p 3p 3p 4p 5p 1m 2m 3m 4m 5m 6m
2 3p 6p
1p 2p 3p 3p 3p 3p 4p 5p 1m 2m 3m 4m 5m
2 3m 6m
1p 2p 3p 3p 3p 3p 4p 5p 6p 1m 2m 3m 4m
2 1m 4m
1c 2c 3c 4c 5c 6c 7c 1p 9p 1m 9m 1s 9s
13 1m 9m 1s 9s 1p 9p 1c 2c 3c 4c 5c 6c 7c
1p 1p 3p 2p 5p 2p 6p 7p 3p 4p 5p 6p 4p
3 1p 4p 7p
1p 1p 2p 3p 2p 3p 4p 4p 5p 5p 6p 7p 7p
2 3p 6p
1p 1p 9p 9p 1m 1m 9m 9m 1s 9s 1s 9s 7c
1 7c
1p 1p 1p 1p 1m 1m 1m 1s 9s 1c 1c 1s 9s
Nooten
1p 1p 1s 9s 1m 9m 1c 2c 3c 4c 5c 6c 7c
1 9p

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
map<char,int>myp;
int save[5][15],cnt;
char sa[5];
char pp[4]={'m','s','p','c'};
bool flag,ans[40],hav[40];

void juqi(int a) //判断是否是七对
{
   for(int i=0;i<34;i++)
   {
      int x=i/9,y=i%9;
      if(!save[x][y])
         continue;
      if(save[x][y]!=2)
         return ;
   }
   //printf("qidui yes
");
   ++cnt,ans[a]=true;
   return ;
}
void jushi(int a) //判断是否是十三幺
{
   for(int i=0;i<3;i++)
   {
      if(save[i][0]!=1&&save[i][0]!=2)
         return ;
      if(save[i][8]!=1&&save[i][8]!=2)
         return ;
      for(int j=1;j<8;j++)
         if(save[i][j])
            return ;
   }
   for(int i=0;i<7;i++)
      if(save[3][i]!=1&&save[3][i]!=2)
         return ;
   ++cnt,ans[a]=true;
   return ;
}
void dfs(int num,int val)
{
   if(flag)
      return ;
   if(num==2)
   {
      for(int i=0;i<4;i++)
      {
         for(int j=0;j<=((i==3)?6:8);j++)
            if(save[i][j]==2) //最后两张牌,肯定是一样的才可能糊
            {
               flag=true;
               if(!ans[val])
                  ++cnt,ans[val]=true;
               return ;
            }
            else if(save[i][j])
               return ;
      }
   }
   for(int i=0;i<4;i++)
   {
      for(int j=0;j<(i==3?7:9);j++)
      {
         if(save[i][j]>=3) //三张一样的牌
         {
            save[i][j]-=3;
            dfs(num-3,val);
            save[i][j]+=3;
            if(flag)
             return ;
         }
         if(!j||j==8||i==3)
            continue;
         if(save[i][j]&&save[i][j-1]&&save[i][j+1])//连续三张同色牌,注意c牌不行
         {
            save[i][j]--,save[i][j-1]--,save[i][j+1]--;
            dfs(num-3,val);
            save[i][j]++,save[i][j-1]++,save[i][j+1]++;
            if(flag)
               return ;
         }
      }
   }
}
bool iscan()
{
   for(int i=0;i<3;i++)
   {
      if(save[i][0]==1&&save[i][1]==0)
         return false;
      int j;
      for(j=1;j<=7;j++) //当为只有1张牌,且左右没牌
      {
         if(save[i][j]==1&&save[i][j-1]==0&&save[i][j+1]==0)
            return false;
      }
      if(save[i][j]==1&&save[i][j-1]==0)
         return false;
   }
   for(int i=0;i<7;i++)
      if(save[3][i]==1)
         return false;
   return true;
}
int main()
{
   myp['m']=0,myp['s']=1,myp['p']=2,myp['c']=3;
   int t;

   scanf("%d",&t);
   while(t--)
   {
      memset(save,0,sizeof(save));
      memset(ans,false,sizeof(ans));
      memset(hav,false,sizeof(hav));
      for(int i=1;i<=13;i++)
      {
         scanf("%s",sa);
         save[myp[sa[1]]][*sa-'0'-1]++;
         int xx=myp[sa[1]]*9+*sa-'0'-1;
         hav[xx]=true; //hav为能够糊的牌
         if(xx%9) //当然c牌有些不能糊也算进去了,不要紧
         {
            if(xx%9==8)
               hav[xx-1]=true;
            else
               hav[xx-1]=hav[xx+1]=true;
         }
         else
            hav[xx+1]=true;
      }
      cnt=0;
      for(int i=0;i<34;i++)
      {
         if(save[i/9][i%9]>=4) //这张牌已经没有了
            continue;
         save[i/9][i%9]++;
         jushi(i);
         if(!hav[i]||!iscan()) //两个剪枝
         {
            save[i/9][i%9]--;
            continue;
         }
         juqi(i);
         flag=false;
         dfs(14,i);
         save[i/9][i%9]--;
      }
      if(!cnt)
      {
         printf("Nooten
");
         continue;
      }
      printf("%d",cnt);
      for(int i=0;i<34;i++)
      {
         if(ans[i])
            printf(" %d%c",i%9+1,pp[i/9]);
      }
      putchar('
');
   }
   return 0;
}


原文地址:https://www.cnblogs.com/riskyer/p/3266726.html