搜索+记忆化搜索
首先研究一下斗地主出牌的特点,发现顺子扔牌快,则根据贪心思路,优先思考顺子
先dfs顺子,再某一时刻,我们认为接下来不再顺子了,那么我们进行第二步:记忆化搜索,得到剩下的牌用其他出牌方式的最优解
Ps. 我直接按照上面那篇题解的正确思路来编,所以一次把noip版、加强版都过了,差别是可以把3张或4张相同的牌拆开来打,有时候更优
Code:
{
card[i]表示点数为i的牌张数
cnt[i]表示,有i张相同的牌,这样的组合有几对
}
uses math;
var
card,cnt:array[0..1000] of longint;
n,qnum,i,ans,x,y,p:longint;
f:array[0..25,0..25,0..25,0..25,0..5] of longint;
function dfs2(a, b, c, d, e:longint):longint;
var
sum:longint;
begin
if f[a][b][c][d][e] <> -1 then exit(f[a][b][c][d][e]);
sum := a + b + c + d + e;
if e = 2 then sum := min(sum, dfs2(a, b, c, d, 0) + 1);
if d > 0 then
begin
if e = 2 then sum := min(sum, dfs2(a, b, c, d - 1, 0) + 1);
if b >= 2 then sum := min(sum, dfs2(a, b - 2, c, d - 1, e) + 1);
if b >= 1 then sum := min(sum, dfs2(a, b - 1, c, d - 1, e) + 1);
if (e > 0) and (a > 0) then sum := min(sum, dfs2(a - 1, b, c, d - 1, e - 1) + 1);
if a > 1 then sum := min(sum, dfs2(a - 2, b, c, d - 1, e) + 1);
sum := min(sum, dfs2(a + 4, b, c, d - 1, e));
sum := min(sum, dfs2(a + 2, b + 1, c, d - 1, e));
sum := min(sum, dfs2(a + 1, b, c + 1, d - 1, e));
sum := min(sum, dfs2(a, b + 2, c, d - 1, e));
end;
if c > 0 then
begin
if b > 0 then sum := min(sum, dfs2(a, b - 1, c - 1, d, e) + 1);
if e > 0 then sum := min(sum, dfs2(a, b, c - 1, d, e - 1) + 1);
if a > 0 then sum := min(sum, dfs2(a - 1, b, c - 1, d, e) + 1);
sum := min(sum, dfs2(a + 3, b, c - 1, d, e));
sum := min(sum, dfs2(a + 1, b + 1, c - 1, d, e));
end;
f[a][b][c][d][e] := sum;
exit(sum);
end;
function get:longint;
var
i:longint;
begin
fillchar(cnt,sizeof(cnt),0);
for i := 1 to 13 do inc(cnt[card[i]]);
exit(dfs2(cnt[1], cnt[2], cnt[3], cnt[4], card[14]));
end;
procedure dfs1(sum:longint);
var
i,j,k:longint;
flag:boolean;
begin
ans := min(ans, sum + get);
for i := 1 to 13 do
for j := 2 to 13 do
if i + j - 1 > 12 then
break else
begin
flag := true;
for k := i to i + j - 1 do
if card[k] < 3 then
begin
flag := false; break;
end;
if flag then
begin
for k := i to i + j - 1 do dec(card[k], 3);
dfs1(sum + 1);
for k := i to i + j - 1 do inc(card[k], 3);
end;
end;
for i := 1 to 13 do
for j := 3 to 13 do
if i + j - 1 > 12 then
break else
begin
flag := true;
for k := i to i + j - 1 do
if card[k] < 2 then
begin
flag := false; break;
end;
if flag then
begin
for k := i to i + j - 1 do dec(card[k], 2);
dfs1(sum + 1);
for k := i to i + j - 1 do inc(card[k], 2);
end;
end;
for i := 1 to 13 do
for j := 5 to 13 do
if i + j - 1 > 12 then
break else
begin
flag := true;
for k := i to i + j - 1 do
if card[k] < 1 then
begin
flag := false; break;
end;
if flag then
begin
for k := i to i + j - 1 do dec(card[k]);
dfs1(sum + 1);
for k := i to i + j - 1 do inc(card[k]);
end;
end;
end;
begin
readln(qnum,n);
fillchar(f,sizeof(f),255);
for p := 1 to qnum do
begin
fillchar(card,sizeof(card),0);
for i := 1 to n do
begin
readln(x,y);
if x = 0 then x := 14;
if x < 3 then
inc(x, 11) else
if x < 14 then
dec(x, 2);
inc(card[x]);
end;
ans := n;
dfs1(0);
writeln(ans);
end;
end.