NOIP2015提高组Day1斗地主

题目

这里写图片描述

分析

仔细看,这道题着实想不到什么优美的算法,那么基本确定方向——dfs。
先分析,这题的花色是没用的
我们再分析,会发现这题的出牌顺序是不影响答案的
那么我们便可以先出牌多的(因为这样答案便会先便小,那么便可以方便后面的剪枝)
也就是我们先打顺子再打带牌!
顺子是没有什么技巧的,便直接暴搜(当然也是先暴搜长度长的)
带牌是有技巧的!
我们发现带牌是不与牌本身的点数有关的
于是我们便可以分别统计有多少种牌是四张的,三张的,两张的,一张的。
最后注意三点:
1.我们可以拆开牌来打
也就是若我想打四带两张单张牌
我们便可以拆三张的拆成两张的和一张的。
或者两张一张的,或者一张两张的。
2.王是不能带出去的,也就是对王是单独出的。
3.2,王是不能顺子的
这样便可以放心的暴搜了。

var
    n,t,x,y,i,ans:longint;
    a:array[0..15] of longint;
    p:array[0..4] of longint;
    toe:array[1..3] of longint=(5,3,2);
procedure dfs(an:longint);
var i,j:longint;
begin
    if an>=ans then exit;j:=0;
    for i:=1 to 4 do j:=j+p[i];
    if j+an<ans then ans:=j+an;
    if p[4]>0 then begin
    dec(p[4]);
    for i:=4 downto 2 do if p[i]>0 then begin
        dec(p[i]);inc(p[i-2]);
        for j:=2 to 4 do
        if p[j]>0 then begin
           dec(p[j]);inc(p[j-2]);
           dfs(an+1);
           inc(p[j]);dec(p[j-2]);
        end;
        inc(p[i]);dec(p[i-2]);
    end;
    for i:=1 to 4 do if p[i]>0 then begin
        dec(p[i]);inc(p[i-1]);
        for j:=1 to 4 do
        if p[j]>0 then begin
           dec(p[j]);inc(p[j-1]);
           dfs(an+1);
           inc(p[j]);dec(p[j-1]);
        end;
        inc(p[i]);dec(p[i-1]);
    end;
    i:=i;
    inc(p[4]);
    end;
    if p[3]>0 then begin
       dec(p[3]);
       for i:=2 to 4 do if p[i]>0 then begin
           dec(p[i]);inc(p[i-2]);dfs(an+1);inc(p[i]);dec(p[i-2]);
       end;
       for i:=1 to 4 do if p[i]>0 then begin
           dec(p[i]);inc(p[i-1]);dfs(an+1);inc(p[i]);dec(p[i-1]);
       end;
       inc(p[3]);
    end;
end;
procedure solve(an:longint);
var i,j,k,jj:longint;
begin
    if an>=ans then exit;
    fillchar(p,sizeof(p),0);
    for i:=1 to 15 do inc(p[a[i]]);
    if p[0]=15 then begin
       ans:=an;exit;
    end;
    dfs(an);
    for k:=1 to 3 do begin
    for i:=1 to 14-toe[k]-1 do
    if a[i]>=k then begin
       for j:=i+1 to 12 do
       if a[j]<k then break;
       if a[j]<k then dec(j);
       if j-i+1<toe[k] then continue;jj:=j;
       for j:=i to i+toe[k]-1 do dec(a[j],k);
       solve(an+1);
       for j:=i+toe[k] to jj do begin
           dec(a[j],k);
           solve(an+1);
       end;
       for j:=i to jj do inc(a[j],k);
    end;
    i:=i;
    end;
end;
begin
    readln(t,n);
    for t:=1 to t do begin
        ans:=13;
        fillchar(a,sizeof(a),0);
        for i:=1 to n do begin
            readln(x,y);
            if (x>=3)and(x<=13) then inc(a[x-2])
            else if x=1 then inc(a[12])
            else if x=2 then inc(a[13])
            else if y=1 then inc(a[14]) else inc(a[15]);
        end;
        if (a[14]>0)and(a[15]>0) then begin
           a[14]:=0;a[15]:=0;
           solve(1);
           a[14]:=1;a[15]:=1;
        end;
        solve(0);
        writeln(ans);
    end;
close(input);close(output);
end.
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值