恶心送命模拟题
暴搜顺子,DP预处理剩下的。 由于官方数据太水,很多情况没有讨论的都能过普通版本,想要测试自己代码正确性的同学们可以交交这道题,有很多dalao给出了hack数据 : Luogu P2540 斗地主 增强版 传送门
具体细节见代码注释
AC code:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 25;
int n, cnt[15], p[5], Ans, dp[6][8][12][24];
// 14 A
// 0 king
template<class T>inline bool chkmin(T &x, T y) { return y < x ? x = y, 1 : 0; }
inline int solve(int i, int j, int k, int w, int king)
{
if(king == 0) return dp[i][j][k][w];
if(king == 1) return dp[i][j][k][w+1]; // 单打
return min(dp[i][j][k][w] + 1, dp[i][j][k][w+2]); //王炸 + 单打
}
int need[4] = { 0, 5, 3, 2 };
void dfs(int now)
{
if(now >= Ans) return;
memset(p, 0, sizeof p); //注意清零
for(int i = 2; i <= 14; i++) p[cnt[i]]++; //统计 4 3 2 1 个的
chkmin(Ans, now + solve(p[4], p[3], p[2], p[1], cnt[0]));
for(int len = 1; len <= 3; len++) //枚举顺子每个数字出现次数
for(int i = 3, j; i <= 14; i++) //枚举起点
{
for(j = i; j <= 14 && cnt[j] >= len; j++) //枚举终点
{
cnt[j] -= len;
if(j - i + 1 >= need[len]) dfs(now+1);
}
while(--j >= i) cnt[j] += len;
}
}
void Pre() //DP预处理
{
memset(dp, 0x3f, sizeof dp);
for(int i = 0; i <= n/4; i++)
for(int j = 0; j <= n/3; j++)
for(int k = 0; k <= n/2; k++)
for(int w = 0; w <= n; w++) if(i*4 + j*3 + k*2 + w <= n)
{
dp[i][j][k][w] = i + j + k + w;
if(i)
{
if(w >= 2) chkmin(dp[i][j][k][w], dp[i-1][j][k][w-2] + 1);
if(k >= 2) chkmin(dp[i][j][k][w], dp[i-1][j][k-2][w] + 1);
chkmin(dp[i][j][k][w], dp[i-1][j][k][w] + 1); // 打 炸弹
chkmin(dp[i][j][k][w], dp[i-1][j][k+2][w]); //拆
chkmin(dp[i][j][k][w], dp[i-1][j][k+1][w+2]); //拆
chkmin(dp[i][j][k][w], dp[i-1][j][k+1][w+2]); //拆
chkmin(dp[i][j][k][w], dp[i-1][j][k][w+4]); //拆
chkmin(dp[i][j][k][w], dp[i-1][j+1][k][w+1]); //拆
}
if(j)
{
if(w >= 1) chkmin(dp[i][j][k][w], dp[i][j-1][k][w-1] + 1);
if(k >= 1) chkmin(dp[i][j][k][w], dp[i][j-1][k-1][w] + 1);
chkmin(dp[i][j][k][w], dp[i][j-1][k][w] + 1); //打 3 个
chkmin(dp[i][j][k][w], dp[i][j-1][k][w+3]); //拆
chkmin(dp[i][j][k][w], dp[i][j-1][k+1][w+1]); //拆
}
if(k) chkmin(dp[i][j][k][w], dp[i][j][k-1][w] + 1), chkmin(dp[i][j][k][w], dp[i][j][k-1][w+2]); // 打 2 个 + 拆
if(w) chkmin(dp[i][j][k][w], dp[i][j][k][w-1] + 1); //打 1 个
}
}
int main ()
{
int T, x, y;
scanf("%d%d", &T, &n);
Pre();
while(T--)
{
memset(cnt, 0, sizeof cnt);
for(int i = 1; i <= n; i++)
{
scanf("%d%d", &x, &y);
if(x == 1) x = 14;// 把 A -> 14
cnt[x]++;
}
Ans = n; dfs(0);
printf("%d
", Ans);
}
}