您的位置:首页 > 其它

HDU - 4431 and HDU - 3391 我们一起打麻将 【dfs暴力模拟】

2017-10-06 20:54 309 查看
HDU - 4431

HDU - 3391

//这两道题是非常相似的, hdu4431要更难一点, 就以这道题来讲解, 会了这道题, 下面那道题也应该会了. 还有一道Uva的11210(题解) 很像, 但是数据相对弱很多, 不加剪枝也能过, 而hdu4431必须要剪枝, 否则会T.

思路:

1:题目意思是问你什么牌能胡, 所以34张牌一张一张枚举过去就行了

2:胡牌的方式有三种 :

第一:七对不同的,四个相同的不算两对

第二:十三幺,1、9筒,1、9条,1、9万,东南西北红中白板发财,这十三张牌里面有一

种牌是两张其余的都是一张

第三:简单的胡牌,先找出一个对, 剩下下的十二张牌组成顺子或者小包子(即三个一样的)

注意点:

1: 每一种牌不能超过4张, 这里特判一下.

2: 组成顺子的只能是筒,条,万. 那特殊的7张牌不能组成顺子. 但可以组成小包子.

3: 找到一个对子后进行dfs查找顺子或者小包子的时候特别要注意一定要剪枝,否则T到死.

AC Code

const int maxn = 100+5;
int cas=1;
char *Ma[] = {"1m","2m","3m","4m","5m","6m","7m","8m","9m",
"1s","2s","3s","4s","5s","6s","7s","8s","9s",
"1p","2p","3p","4p","5p","6p","7p","8p","9p",
"1c","2c","3c","4c","5c","6c","7c"};
inline int change(char *s)
{
for(int i=0;i<34;i++){
if(strcmp(s,Ma[i]) == 0)
return i;
}
}

bool check(int x)    //判断是否可以组成顺子.
{
if(x>=0 && x<=6) return true;
else if(x>=9 && x<= 15) return true;
else if(x>=18 && x <= 24) return true;
else return false;
}

int c[maxn];
inline bool dfs(int deep)
{
if(deep >=4) return true;
int flag = 0;
for(int i=0;i<34;i++){
int ff = 0;
if(c[i]>=3){
ff++;
c[i] -= 3;
if(dfs(deep+1)) return true;
c[i] += 3;
}
if(check(i) && c[i] > 0 && c[i+1] > 0 && c[i+2] > 0){
ff++;
c[i]--; c[i+1]--; c[i+2]--;
if(dfs(deep+1)) return true;
c[i]++; c[i+1]++; c[i+2]++;
}
//以下两个个剪枝是最重要的, 否则会T.
if(c[i] && !ff) return false; //这种牌有但是不符合顺子或者小包子结束这层搜索
if(c[i]) break;
//这里减枝是因为上面的搜索下次遍历的时候还会继续从他这遍历,所以就不用继续下去
}
return false;
}

inline bool check1()
{
for(int i=0;i<34;i++){
if(c[i]>=2) {
c[i] -= 2;
if(dfs(0)) return true;
c[i] += 2;
}
}
return false;
}

inline bool check2(int x)
{
int cnt1 = 0,cnt2 = 0,sum = 0;
for(int i=0;i<34;i++){
if(c[i] == 2) cnt1++;
if(i>=27 && c[i] >0) cnt2++,sum+=c[i];
if((i <= 26 && (i%9 == 0 || i%9 == 8)) && c[i] > 0) cnt2++,sum+=c[i];
}
if(cnt1 == 7 || (cnt2 == 13 && sum == 14)) return true;
return false;
}

int ans[maxn];
void solve()
{
int mj[maxn];
for(int i=0;i<13;i++){
char s[10];
scanf("%s",s);
mj[i] = change(s);
}
bool flag = 0; int cnt = 0;
for(int i=0;i<34;i++){
Fill(c,0);
for(int j=0;j<13;j++) c[mj[j]]++;
if(c[i]>=4) continue;
c[i]++;
if(check2(i)) {
flag = 1;
ans[cnt++] = i;
}
else if(check1()) {
flag = 1;
ans[cnt++] = i;
}
}
if(!flag) puts("Nooten");
else{
printf("%d",cnt);
for(int i=0;i<cnt;i++){
printf(" %s",Ma[ans[i]]);
}
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: