这真是道大火题。

因为保证数据随机,所以开始很多人直接用搜索 + 贪心水过去了,后来,为了遏制骗分这种不良风气的传播,各大 OJ 相继推出了斗地主加强版……

正解:

先爆搜顺子,枚举打或不打,打多少张。对于剩下的散牌做 DP,最少需要多少次打完。

设 \(f[i][j][k][l]\) 表示四张牌的剩 \(i\) 张,三张牌的剩 \(j\) 张,两张牌的剩 \(k\) 张,一张牌的剩 \(l\) 张,最少需要多少次打完。因为不考虑打顺子,所以点数与打完的次数无关。然后按照题目除顺子之外的打法转移即可。

与加强版的区别就是网能不能看成普通对子。

注意

记忆化搜索的值莫名其妙的变化了多半是数组越界。

搜索不要没想清楚就随便剪枝,可能不知不觉中就剪挂了。

代码是加强版的。

#include <bits/stdc++.h>
using namespace std; #define N 25
#define RG register inline int gi()
{
RG int ret; RG char ch;
ret=0, ch=getchar();
while (ch < '0' || ch > '9')
ch=getchar();
while (ch >= '0' && ch <= '9')
ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();
return ret;
} int tong[N],f[N][N][N][N];
int ans,n; inline int cal(int i,int j,int k,int l)
{
if (f[i][j][k][l] || (!i && !j && !k && !l))
return f[i][j][k][l];
RG int ret;
ret=i+j+k+l;
if (i)
ret=min(ret,min(cal(i-1,j+1,k,l+1),cal(i-1,j,k+2,l)));
if (j)
ret=min(ret,cal(i,j-1,k+1,l+1));
if (k)
ret=min(ret,cal(i,j,k-1,l+2));
if (i && k > 1)
ret=min(ret,cal(i-1,j,k-2,l)+1);
if (i && l > 1)
ret=min(ret,cal(i-1,j,k,l-2)+1);
if (j && k)
ret=min(ret,cal(i,j-1,k-1,l)+1);
if (j && l)
ret=min(ret,cal(i,j-1,k,l-1)+1);
return f[i][j][k][l]=ret;
} inline void dfs(int dep)
{
if (dep >= ans)
return;
RG int i,j,k,l,tot;
for (i=3; i<11; ++i)
{
if (!tong[i])
continue;
tot=1, j=i+1;
while (tong[j])
tot++, j++;
if (tot < 5)
continue;
for (j=5; j<=tot; ++j)
{
for (k=0; k<j; ++k)
tong[i+k]--;
dfs(dep+1);
for (k=0; k<j; ++k)
tong[i+k]++;
}
}
for (i=3; i<13; ++i)
{
if (tong[i] < 2)
continue;
tot=1, j=i+1;
while (tong[j] >= 2)
tot++, j++;
if (tot < 3)
continue;
for (j=3; j<=tot; ++j)
{
for (k=0; k<j; ++k)
tong[i+k]-=2;
dfs(dep+1);
for (k=0; k<j; ++k)
tong[i+k]+=2;
}
}
for (i=3; i<14; ++i)
{
if (tong[i] < 3)
continue;
tot=1, j=i+1;
while (tong[j] >= 3)
tot++, j++;
if (tot < 2)
continue;
for (j=2; j<=tot; ++j)
{
for (k=0; k<j; ++k)
tong[i+k]-=3;
dfs(dep+1);
for (k=0; k<j; ++k)
tong[i+k]+=3;
}
}
i=j=k=l=0;
for (tot=2; tot<15; ++tot)
if (!tong[tot])
continue;
else if (tong[tot] == 1)
l++;
else if (tong[tot] == 2)
k++;
else if (tong[tot] == 3)
j++;
else if (tong[tot] == 4)
i++;
if (tong[0] == 2)
ans=min(ans,dep+cal(i,j,k,l)+1);
l+=tong[0];
// if (tong[0] == 2)
// k++;
// else if (tong[0] == 1)
// l++;
ans=min(ans,dep+cal(i,j,k,l));
} inline void work()
{
RG int i,x;
for (i=1; i<=n; ++i)
x=gi(), tong[x]++, x=gi();
tong[14]=tong[1];
ans=n;
dfs(0);
printf("%d\n",ans);
for (i=0; i<15; ++i)
tong[i]=0;
} int main()
{
RG int t;
t=gi(), n=gi();
while (t--)
work();
return 0;
}

NOIP 2014【斗地主】的更多相关文章

  1. NOIP 2014 提高组 题解

    NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...

  2. Luogu 2668 NOIP 2015 斗地主(搜索,动态规划)

    Luogu 2668 NOIP 2015 斗地主(搜索,动态规划) Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来 ...

  3. Luogu 1351 NOIP 2014 联合权值(贪心,计数原理)

    Luogu 1351 NOIP 2014 联合权值(贪心,计数原理) Description 无向连通图 G 有 n 个点,n-1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi, ...

  4. noip 2014 提高组初赛

    noip 2014 提高组初赛 一. TCP协议属于哪一层协议( ) A. 应用层 B. 传输层 C. 网络层 D. 数据链路层 B TCP(传输控制协议) 若有变量int a; float: x, ...

  5. 洛谷P1328==codevs3716 生活大爆炸版石头剪刀布[NOIP 2014 day1 T1]

    P1328 生活大爆炸版石头剪刀布 1.8K通过 2.6K提交 题目提供者2014白永忻 标签模拟NOIp提高组2014 难度普及- 提交该题 讨论 题解 记录 最新讨论 Who can help m ...

  6. noip 2014 总结

    2014 年的noip 已经结束了,成绩从个人而言不是特别的理想,从今年题的逗的程度,本来是个xxx 就被玩脱了= = 当然现在后悔事没有用的了,不过第二天全屏技术的在最后一小时看到了两道题的错误,然 ...

  7. NOIP 2014 pj & tg

    由于我太弱,去了pj组= = ============================== T1: 傻逼暴力 T2: 傻逼暴力+判断+更新 T3: 手画一下就知道了.算出这个点在第几圈,再使劲yy下在 ...

  8. [NOIP 2014复习]第三章:动态规划——NOIP历届真题回想

    背包型动态规划 1.Wikioi 1047 邮票面值设计 题目描写叙述 Description 给定一个信封,最多仅仅同意粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定全部的邮票数量都 ...

  9. 基础算法(搜索):NOIP 2015 斗地主

    Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3& ...

随机推荐

  1. vuex 深入理解

    参考自:https://mp.weixin.qq.com/s?src=11&timestamp=1528275978&ver=922&signature=ZeHPZ2ZrLir ...

  2. UDP通信接收端,接收二维数组,内容为0与1

    1: using System; 2: using System.Net; 3: using System.Net.Sockets; 4: using System.Text; 5:   6:   7 ...

  3. Leetcode Array 15 3sum

      思考的方向不对,即使用了多于别人几倍的时间,也不一定能够达到终点. 我的错误的想法(可以跳过):在leetcode上面做的第四道题,走路一个很大的弯路,收到之前做过的 Container With ...

  4. Java实现分布式锁方式

    1.数据库乐观锁 2.redis 3.zookeeper

  5. 一步一步实现一个简单的OS(简单的让boot载入setup)

    这次直接写用boot载入setup模块. 文件系统就先不弄了,以后再说, 咱先整个转简单的载入器. 我把软盘引导改成硬盘了,由于硬盘的读扇区函数简单一些. 这里没有做硬盘的mbr区,我认为在如今我的这 ...

  6. windows下使用Eclipse编译执行MapReduce程序 Hadoop2.6.0/Ubuntu

    一.环境介绍 宿主机:windows8 虚拟机:Ubuntu14.04 hadoop2.6伪分布:搭建教程http://blog.csdn.net/gamer_gyt/article/details/ ...

  7. Linux trace使用入门

    概念 trace 顾名思义追踪信息,可通俗理解为一种高级打印机制,用于debug,实现追踪kernel中函数事件的框架.源代码位于:\kernel\trace\trace.c,有兴趣能够研究 撰写不易 ...

  8. JavaScript--基于对象的脚本语言学习笔记(一)

    1.两种嵌入js的方式    使用javascript前缀构建url:<a href="javascript:alert('执行JavaScript. .')">执行j ...

  9. git是一种分布式代码管理工具,git通过树的形式记录文件的更改历史,比如: base'<--base<--A<--A' ^ | --- B<--B' 小米工程师常常需要寻找两个分支最近的分割点,即base.假设git 树是多叉树,请实现一个算法,计算git树上任意两点的最近分割点。 (假设git树节点数为n,用邻接矩阵的形式表示git树:字符串数组matrix包含n个字符串,每个字符串由字符'0

    // ConsoleApplication10.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream& ...

  10. android 导入项目 项目中文字乱码问题

    乱码问题出现了几次,一直没有在意,今天又出现了,现总结如下: eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的.一般默认都是UTF-8或者GBK,当从外部导入的一个工 ...