[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; }