XDU Problem 1105 - 打麻将 (模拟) [12/11/17 daily] #by Plato

6 篇文章 0 订阅

http://acm.xidian.edu.cn/land/problem/detail?problem_id=1105

前年校赛的一道题,去年校赛前自己模拟做了那套,这道题没有出。现在来补了。

题意:一种新的麻将,只有一种花色但有M张牌,给出N张牌,求所有的听牌(只考虑2+3X的胡牌规则)。

把前面那道题改改就OK了。

#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int N,M;
int num[300],tile[300],t[300],n[300];
bool used[300];

bool Fu(int newt)
{
	int ok = false;
	num[newt]++;
	for (int i = 1;i <= N;i++) t[i] = tile[i];
	t[N+1] = newt;
	t[0] = t[N+2] = -1;
	sort(t+1,t+N+2);

	for (int i = 1;i <= N+1;i++) if (t[i] != t[i-1])
	{
		for (int j = 1;j <= M;j++) n[j] = num[j];
		memset(used,0,sizeof(used));
		int tt = t[i];
		if (n[tt] < 2) continue;
		used[i] = used[i+1] = true;
		n[tt] -= 2;

		int j;
		for (j = 1;j <= N+1;j++) if (!used[j])
		{
			int t1 = t[j];
			if (n[t1] >= 3)
			{
				n[t1] -= 3;
				used[j] = used[j+1] = used[j+2] = 1;
			}
			while (n[t1] && n[t1+1] && n[t1+2])
			{
				n[t1] --,n[t1+1]--,n[t1+2]--;
				for (int k1 = j+1;k1 <= N+1;k1++) if (!used[k1] && t[k1] == t1+1)
				{
					used[k1] = 1;
					break;
				}
				for (int k1 = j+1;k1 <= N+1;k1++) if (!used[k1] && t[k1] == t1+2)
				{
					used[k1] = 1;
					break;
				}
			}
			if (n[t1]) break;
		}

		if (j == N+2)
		{
			ok = true;
			break;
		}
	}

	num[newt]--;
	return ok;
}

int main()
{
    freopen("test.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while (T--)
    {
        memset(num,0,sizeof(num));
        scanf("%d%d",&N,&M);
        for (int i = 1; i <= N; i++)
        {
        	scanf("%d",&tile[i]);
        	num[tile[i]]++;
        }

		int ans[300],suma = 0;
		for (int i = 1;i <= M;i++) if (num[i] < 4)
		{
			if (Fu(i)) ans[++suma] = i;
		}

        cout<<suma;
        for (int i = 1;i <= suma;i++) cout<<" "<<ans[i];
        cout<<endl;
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值