代码很长,注释不少,不知道哪里可以优化?希望不吝赐教
//
#include<iostream>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<cstdio>
#include<string>
#include<algorithm>
#include<utility>
#include<limits.h>
#include<map>
#include<set>
using namespace std;
int t, n, ans;
int card_box[20];
void read()
{
memset(card_box, 0, sizeof(card_box));
for(int i = 0; i < n; i++)
{
int a, b;
scanf("%d %d", &a, &b);
switch (a)
{
case 0:
card_box[15]++;
break;
case 1:
card_box[14]++;
break;
default:
card_box[a]++;
break;
}
}
}
void dfs(int x)
{
// 非最优,剪枝
if(x >= ans)
{
return ;
}
// 单顺子 不带2不带王
int dsz = 0;
for(int i = 3; i < 15; i++)
{
// 单顺子断了
if(card_box[i] < 1)
{
dsz = 0;
}
else
{
dsz++;
// 可以出了
if(dsz >= 5)
{
for(int j = i; j > i - dsz; j--)
{
card_box[j]--;
}
dfs(x + 1);
for(int j = i; j > i - dsz; j--)
{
card_box[j]++;
}
}
}
}
// 双顺子 不带2不带王
int ssz = 0;
for(int i = 3; i < 15; i++)
{
// 双顺子断了
if(card_box[i] < 2)
{
ssz = 0;
}
else
{
ssz++;
// 可以出了
if(ssz >= 3)
{
for(int j = i; j > i - ssz; j--)
{
card_box[j] -= 2;
}
dfs(x + 1);
for(int j = i; j > i - ssz; j--)
{
card_box[j] += 2;
}
}
}
}
// 三顺子 不带2不带王
int tsz = 0;
for(int i = 3; i < 15; i++)
{
// 三顺子断了
if(card_box[i] < 3)
{
ssz = 0;
}
else
{
ssz++;
// 可以出了
if(ssz >= 2)
{
for(int j = i; j > i - ssz; j--)
{
card_box[j] -= 3;
}
dfs(x + 1);
for(int j = i; j > i - ssz; j--)
{
card_box[j] += 3;
}
}
}
}
// 带牌
for(int i = 2; i < 15; i++)
{
// 牌太少,过掉
if(card_box[i] < 3)
{
continue;
}
// 出三张,带牌
card_box[i] -= 3;
// 三带一,带单张
for(int j = 2; j < 15; j++)
{
// 没牌/是自己无法带牌, 过掉
if(j == i || card_box[j] < 1)
{
continue;
}
// 出掉被带的牌
card_box[j]--;
dfs(x + 1);
card_box[j]++;
}
// 三带二,带一对
for(int j = 2; j < 15; j++)
{
// 没对子/是自己无法带牌, 过掉
if(j == i || card_box[j] < 2)
{
continue;
}
// 出掉被带的一对
card_box[j] -= 2;
dfs(x + 1);
card_box[j] += 2;
}
card_box[i] += 3;
// 三张过掉
if(card_box[i] == 3)
{
continue;
}
// 出四张,带牌
card_box[i] -= 4;
// 四带二,带两张单牌
for(int j = 2; j < 15; j++)
{
// 没牌/是自己无法带牌, 过掉
if(j == i || card_box[j] < 1)
{
continue;
}
// 出掉被带的第一张单牌
card_box[j]--;
// 找第二张单牌
for(int k = 2; k < 15; j++)
{
// 没单牌/已经带了/是自己无法带牌, 过掉
if(k == i || k == j || card_box[k] < 1)
{
continue;
}
// 出掉被带的第二张单牌
card_box[k]--;
dfs(x + 1);
card_box[k]++;
}
card_box[j]++;
}
// 四带二,带两个对子
for(int j = 2; j < 15; j++)
{
// 没对子/是自己无法带牌, 过掉
if(j == i || card_box[j] < 2)
{
continue;
}
// 出掉被带的第一个对子
card_box[j] -= 2;
// 找第二个对子
for(int k = 2; k < 15; j++)
{
// 没对子/已经带了/是自己无法带牌, 过掉
if(k == i || k == j || card_box[k] < 2)
{
continue;
}
// 出掉被带的第二张单牌
card_box[k] -= 2;
dfs(x + 1);
card_box[k] += 2;
}
card_box[j] += 2;
}
card_box[i] += 4;
}
// 把剩下的单牌出完
for(int i = 2; i <= 15; i++)
{
if(card_box[i])
{
x++;
}
}
ans = min(ans, x);
}
int main()
{
cin >> t >> n;
while(t--)
{
ans = 1 << 30;
read();
dfs(0);
printf("%d\n", ans);
}
}