Luogu P2540 NOIP2015提高组 斗地主 加强版 题解 [ 紫 ] [ 深搜 ] [ 剪枝 ]
斗地主:一步一步推性质就能做出来的剪枝题。
这题思路和小木棒的剪枝思路极其相似,剪枝的角度都差不多。
其实大部分搜索剪枝题都是先观察性质,列出性质后选择几个比较关键且代码好写的性质进行剪枝,特别要注意避免重复搜索相同状态的剪枝。同时注意想好了之后再写代码。
并且大部分搜索题会把正向的搜索树 hack 得很大,当被卡的时候不妨试试倒着搜索,可能有奇效。
思路
观察题目,我们可以发现如下几点性质:
- 出牌的顺序不影响最终的结果,先出某一组牌和后出某一组牌本质是一样的。
- 最后只剩下单牌、对子、三张牌、炸弹和王炸的时候,我们可以贪心地扫一遍统计至少存在一张牌的码数的个数,特判掉大小王得出答案。
- 在顺子和带牌中,顺子打出的方案数一般比带牌的方案数更少。
因此,我们可以设计出如下剪枝方案:
- 将搜索阶段拆解为 \(6\) 步,依次完成。分别是三顺子、双顺子、单顺子、四带二、三带一和二、最后剩下的统一出掉,大王小王绑一起出。
- 记录下当前的搜索阶段 \(p\),以及上一次在同阶段最后搜索到的牌 \(lst\)。每次接着 \(lst\) 后面来搜索,避免搜到重复状态。
- 把三顺子、双顺子、单顺子、四带二、三带一和二全部出完之后,我们可以线性扫一遍算出最终的答案,避免了搜索多余状态。
实现的时候对每个搜索阶段分步实现,代码在写顺子和带牌内部时可以稍作修改之后重复利用。
时间复杂度玄学,但是能过大部分数据。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
using pi=pair<int,int>;
/*
三顺子 1
双顺子 2
单顺子 3
四带二 4
三带一、二 5
最后剩下的统一出掉,大王小王绑一起出。
1~11 3~K
12 A
13 2
14 little
15 big
*/
int tot[20],ans=0x3f3f3f3f,now=0,n;
void dfs(int p,int lst)
{
if(p>=6)
{
int cur=0;
for(int i=1;i<=15;i++)if(tot[i])cur++;
if(tot[14]&&tot[15])cur--;
ans=min(ans,now+cur);
return;
}
if(p==1)
{
int pre=0;
for(int i=1;i<=12;i++)
{
if(tot[i]>=3)pre++;
else pre=0;
if(pre>=2&&i>=lst)
{
int tmp[20];
memcpy(tmp,tot,sizeof(tmp));
tot[i]-=3;
for(int j=2;j<=pre;j++)
{
tot[i-j+1]-=3;
now++;
dfs(p,i);
now--;
}
memcpy(tot,tmp,sizeof(tmp));
}
}
dfs(p+1,1);
return;
}
if(p==2)
{
int pre=0;
for(int i=1;i<=12;i++)
{
if(tot[i]>=2)pre++;
else pre=0;
if(pre>=3&&i>=lst)
{
int tmp[20];
memcpy(tmp,tot,sizeof(tmp));
tot[i]-=2;
tot[i-1]-=2;
for(int j=3;j<=pre;j++)
{
tot[i-j+1]-=2;
now++;
dfs(p,i);
now--;
}
memcpy(tot,tmp,sizeof(tmp));
}
}
dfs(p+1,1);
return;
}
if(p==3)
{
int pre=0;
for(int i=1;i<=12;i++)
{
if(tot[i]>=1)pre++;
else pre=0;
if(pre>=5&&i>=lst)
{
int tmp[20];
memcpy(tmp,tot,sizeof(tmp));
tot[i]-=1;
tot[i-1]-=1;
tot[i-2]-=1;
tot[i-3]-=1;
for(int j=5;j<=pre&&i-j+1>=1;j++)
{
tot[i-j+1]-=1;
now++;
dfs(p,i);
now--;
}
memcpy(tot,tmp,sizeof(tmp));
}
}
dfs(p+1,1);
return;
}
if(p==4)
{
for(int i=1;i<=13;i++)
{
if(tot[i]>=4)
{
tot[i]-=4;
for(int j=1;j<=15;j++)
{
if(tot[j]<=0)continue;
for(int k=1;k<=15;k++)
{
if(tot[k]<=0)continue;
if(tot[j]&&tot[k]&&(j!=k||tot[j]>=2))
{
tot[j]--;
tot[k]--;
now++;
dfs(p,i);
tot[j]++;
tot[k]++;
now--;
}
if(tot[j]>=2&&tot[k]>=2&&(j!=k||tot[j]>=4))
{
tot[j]-=2;
tot[k]-=2;
now++;
dfs(p,i);
tot[j]+=2;
tot[k]+=2;
now--;
}
}
}
tot[i]+=4;
}
}
dfs(p+1,1);
return;
}
if(p==5)
{
for(int i=1;i<=13;i++)
{
if(tot[i]>=3)
{
tot[i]-=3;
for(int j=1;j<=15;j++)
{
if(tot[j]>=1)
{
tot[j]--;
now++;
dfs(p,i);
tot[j]++;
now--;
}
if(tot[j]>=2)
{
tot[j]-=2;
now++;
dfs(p,i);
tot[j]+=2;
now--;
}
}
tot[i]+=3;
}
}
dfs(p+1,1);
return;
}
}
void solve()
{
memset(tot,0,sizeof(tot));
ans=0x3f3f3f3f;
now=0;
for(int i=1;i<=n;i++)
{
int a,b;
cin>>a>>b;
if(3<=a&&a<=13)tot[a-2]++;
else if(a<3&&a>0)tot[a+11]++;
else tot[b+13]++;
}
dfs(1,1);
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t>>n;
while(t--)solve();
return 0;
}
Luogu P2540 NOIP2015提高组 斗地主 加强版 题解 [ 紫 ] [ 深搜 ] [ 剪枝 ]的更多相关文章
- [NOIP2015 提高组] 运输计划题解
题目链接:P2680 [NOIP2015 提高组] 运输计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 看了好长时间题解才终于懂的,有关lca和二分答案的题解解释的不详细,一时 ...
- 一本通例题-生日蛋糕——题解<超强深搜剪枝,从无限到有限>
题目传送 显然是道深搜题.由于蛋糕上表面在最底层的半径确认后就确认了,所以搜索时的面积着重看侧面积. 找维度/搜索面临状态/对象:当前体积v,当前外表面面积s,各层的半径r[],各层的高度h[]. 可 ...
- 【题解】NOIP2015提高组 复赛
[题解]NOIP2015提高组 复赛 传送门: 神奇的幻方 \([P2615]\) 信息传递 \([P2661]\) 斗地主 \([P2668]\) 跳石头 \([P2678]\) 子串 \([P26 ...
- 洛谷 P2678 & [NOIP2015提高组] 跳石头
题目链接 https://www.luogu.org/problemnew/show/P2678 题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布 ...
- 刷题总结——子串(NOIP2015提高组)
题目: 题目背景 NOIP2015 提高组 Day2 T2 题目描述 有两个仅包含小写英文字母的字符串 A 和 B .现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在 ...
- NOIP2015 提高组] 运输计划
码农题啊兄弟们. 随便考虑二分一下,然后发现要取一条满足性质的边. 被所有大于\(mid\)的路径都覆盖,取了之后能把他们都弄到小于\(mid\) 那就树上差分再处理一下. 写了\(180h\),老年 ...
- [NOIP2015] 提高组 洛谷P2615 神奇的幻方
题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...
- 洛谷-神奇的幻方-NOIP2015提高组复赛
题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,--,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...
- 【数据结构】运输计划 NOIP2015提高组D2T3
[数据结构]运输计划 NOIP2015提高组D2T3 >>>>题目 [题目描述] 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航 ...
- 【二分查找】 跳石头NOIP2015提高组 D2T1
[二分查找]跳石头NOIP2015提高组 D2T1 >>>>题目 [题目描述] 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石 ...
随机推荐
- Codeforces Round 881 (Div
E. Tracking Segments 给定初始长度为n,且全为0的序列a,然后给出m个线段,如果一个线段中1的个数严格大于0的个数,那么该线段称为一个漂亮线段,现在给出q次操作,每次操作使得序列a ...
- VUE3 使用资源路径加载
1.使用场景 有些情况下,我需要使用组件路径动态的方式加载组件. 2.实现方法 import { defineAsyncComponent } from 'vue'; /** * 根据view组件路径 ...
- ARCGIS 拓扑检查步骤与修正拓扑错误技巧
转自http://xygszsh.blog.163.com/blog/static/19221517201111831348533/,写得没有说多好,贵在详细. 将数据装载如个人地理数据库,用拓扑功能 ...
- 鸿蒙UI开发快速入门 —— part04: 组件的UI逻辑复用
1.为什么要复用? 从鸿蒙UI开发快速入门 -- part02: 组件开发文章中我们学习到,build()函数是我们构建用户UI界面的入口函数,在该函数中完成UI样式定义以及事件定义. 实际的项目开发 ...
- 中电金信:云原生时代IT基础设施管理利器——基础设施即代码(IaC)
在数字化转型.零售业务快速发展.信创建设驱动下,应用架构.技术架构.基础架构都已向云原生快速演进,银行业IT基础设施管理产生了非常大的变化,当前银行业,正在开展新一轮的核心应用系统重构.基础平台统一 ...
- [MySQL]数据库修复(Example:1146 Error )
删除数据库自带的表,导致的异常问题修复方法如下 运行cmd,查询MYSQL所在位置 where mysql cd到MySQL安装目录的bin目录下 执行命令 mysql_upgrade -u root ...
- Consul 命令(CLI)
Consul通过一个非常简单易用的命令行界面(CLI)进行控制.Consul只是一个单一的命令行应用程序:Consul. 然后,这个应用程序将取代诸如" agent"或" ...
- 『玩转Streamlit』--集成Plotly
之前介绍了如何在Streamlit App中使用Matplotlib库来绘图. 本篇介绍 Steamlit结合Poltly的方法,相比于Matplotlib,Poltly的交互性更强, 更适合在Web ...
- Qt编写安防视频监控系统38-onvif校时
一.前言 在视频监控系统中,对摄像机进行时间设置也是很有必要的,这样就和服务器或者软件这边统一了时间,一般在摄像机的画面上可以设置OSD标识当前时间,这样存储到视频文件中回放的时候,也能和本地的时间一 ...
- Qt音视频开发27-Onvif设备搜索
一.前言 最近业余时间主要研究音视频开发这块,前面的文章写了好多种视频监控内核,一旦将这些内核搞定以后,视频监控的相关功能水到渠成.做视频监控系统,绕不过onvif这玩意,这玩意主要就是为了统一一个大 ...