[BZOJ 1028] [JSOI2007] 麻将 【枚举+贪心判断】

题目链接:BZOJ - 1028

 

题目分析

枚举听的是哪种牌,再枚举成对的是哪种牌,再贪心判断:

从1到n枚举每一种牌,如果这种牌的个数小于0,就返回不合法。

将这种牌的张数 % 3, 剩下的只能和 i + 1, i + 2 这两种牌构成顺,所以 Num[i + 1] -= Num[i]; Num[i + 2] -= Num[i];

牌的种类要枚举到 n + 2,因为第 n - 1 和第 n 种牌可能会减掉 n + 1,n + 2 的牌。

 

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>

using namespace std;

const int MaxN = 400 + 5;

int n, m, Top;
int Cnt[MaxN], Num[MaxN], Ans[MaxN];

int main() 
{
	scanf("%d%d", &n, &m);
	int a;
	for (int i = 1; i <= 3 * m + 1; ++i) 
	{
		scanf("%d", &a);
		++Cnt[a];
	}
	bool Flag;
	for (int i = 1; i <= n; ++i) 
	{
		for (int j = 1; j <= n + 2; ++j) Num[j] = Cnt[j];
		++Num[i];
		for (int j = 1; j <= n; ++j)
		{
			if (Num[j] < 2) continue;
			Num[j] -= 2;
			Flag = true;
			for (int k = 1; k <= n + 2; ++k) 
			{
				if (Num[k] < 0) 
				{
					Flag = false;
					break;
				}
				Num[k] %= 3;
				Num[k + 1] -= Num[k];
				Num[k + 2] -= Num[k];
			}
			if (Flag) 
			{
				Ans[++Top] = i;
				break;
			}
			for (int k = 1; k <= n + 2; ++k) Num[k] = Cnt[k];
			++Num[i];
		}
	}
	if (Top == 0) printf("NO\n");
	else 
	{
		for (int i = 1; i <= Top - 1; ++i) printf("%d ", Ans[i]);
		printf("%d\n", Ans[Top]);
	}
	return 0;
}

  

posted @ 2015-03-08 11:06  JoeFan  阅读(290)  评论(0编辑  收藏  举报