【题解】LuoGu2668/noip2015:斗地主

255 篇文章 0 订阅
53 篇文章 0 订阅


原题传送门


参考自这篇题解

搜索+记忆化搜索

首先研究一下斗地主出牌的特点,发现顺子扔牌快,则根据贪心思路,优先思考顺子

先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.


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值