这真是道大火题。

因为保证数据随机,所以开始很多人直接用搜索 + 贪心水过去了,后来,为了遏制骗分这种不良风气的传播,各大 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;
}

最新文章

  1. android之SharedPreferes
  2. Head First 设计模式--1策略模式 组合优于继承
  3. uoj #9. 【UTR #1】vfk的数据 水题
  4. 基于W5500的嵌入式SNMP代理端实现
  5. 项目源码--Android迷幻岛屿综合游戏
  6. perl 递归地遍历目录下的文件
  7. LoadRunner日志(归档记录,以便自己查阅)
  8. 萝卜德森的sublime笔记中文翻译版
  9. Dreamweaver使用过程的小技巧
  10. BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆
  11. 微信获取企业token流程
  12. 基于STM8的TIM定时器操作---STM8-第三章
  13. iptables防火墙规则的添加、删除、修改、保存
  14. redis两种持久化
  15. [VS] - &quot;包含了重复的“Content”项。.NET SDK 默认情况下包括你项目中的“Content”项。
  16. ORACLE-016:ora-01720 授权选项对于&#39;xxxx&#39;不存在
  17. Windows 环境变量立即生效
  18. MySQL缓存机制详解(一)
  19. CentOS配置yum源(补充)
  20. Daily Scrum (2015/10/31)

热门文章

  1. 怎样推断server为虚拟机还是物理真机?
  2. 动态载入Layout 与 论Activity、 Window、View的关系
  3. DevOps必备的20款顶级工具
  4. 利用DataSet部分功能实现网站登录
  5. arcgis水文分析
  6. 配置Spring的用于解决懒加载问题的过滤器
  7. Excel COM组件使用的注意事项和一些权限问题(转载)
  8. JAVA进阶-多线程(2)
  9. ArrayList和Vector的区别?HashMap和HashTable的区别?StringBuilder、StringBuffer和String的区别?
  10. 【BZOJ3796】Mushroom追妹纸 二分+hash