dfs。其实是很麻烦的模拟题。三种和法,每次枚举一张牌(每类牌不能超过4张),然后分别判断三种情况。注意杠+5对 != 7对,然后国士无双(为啥想起了中华小当家)和七对会有所重叠,所以必须分开考虑。
难得写个不那么“恶心”的代码。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int mj[36];
char s[5], m2[9] = "mspc";
int m1[255], ans[36];
int th[15] = {0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33};
bool check1()
{
int a[6];
memset(a, 0, sizeof(a));
for(int i = 0; i < 13; i++)a[mj[th[i]]]++;
if(a[2] == 1 && a[1] == 12)return 1;
return 0;
}
bool check2()
{
int k = 0;
for(int i = 0; i < 34; i++)if(mj[i] == 2)k++;
return k == 7;
}
bool dfs(int k, int p, int q)
{
if(k == 34 || (p == 4 && q == 1))return 1;
if(!mj[k])return dfs(k + 1, p, q);
bool flag;
if(mj[k] >= 3)
{
mj[k] -= 3;
flag = dfs(k, p + 1, q);
mj[k] += 3;
if(flag)return 1;
}
if(mj[k] >= 2 && !q)
{
mj[k] -= 2;
flag = dfs(k, p, q + 1);
mj[k] += 2;
if(flag)return 1;
}
if(k % 9 < 7 && k / 9 < 3 && mj[k + 1] && mj[k + 2])
{
mj[k]--; mj[k + 1]--; mj[k + 2]--;
flag = dfs(k, p + 1, q);
mj[k]++; mj[k + 1]++; mj[k + 2]++;
if(flag)return 1;
}
return 0;
}
int main()
{
//freopen("input.txt", "r", stdin);
int t, k;
m1['m'] = 0;m1['s'] = 1;m1['p'] = 2;m1['c'] = 3;
scanf("%d", &t);
while(t--)
{
memset(mj, 0, sizeof(mj));
for(int i = 0; i < 13; i++)
{
scanf("%s", s);
k = s[0] - '0' - 1 + 9 * m1[s[1]];
mj[k]++;
}
k = 0;
for(int i = 0; i < 34; i++)if(mj[i] < 4)
{
mj[i]++;
if(check1() || check2() || dfs(0, 0, 0))ans[k++] = i;
mj[i]--;
}
if(k)
{
printf("%d", k);
for(int i = 0; i < k; i++)printf(" %d%c", ans[i] % 9 + 1, m2[ans[i] / 9]);
puts("");
}
else puts("Nooten");
}
return 0;
}