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

Description

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。

具体规则如下:

Input

第一行包含用空格隔开的2个正整数Tn,表示手牌的组数以及每组手牌的张数。

接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。 特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。

Output

共T行,每行一个整数,表示打光第i手牌的最少次数。

Sample Input

1 8

7 4

8 4

9 1

10 4

11 1

5 1

1 4

1 1

Sample Output

3

Http

Luogu:https://www.luogu.org/problem/show?pid=2668

Source

搜索,动态规划

解决思路

题目中给出的出牌规则比较复杂,我们简单地分一下类

第一类:牌的数字与出牌方式没有关系:单张,对子,三张,双王,三带一,三带二,四带二,炸弹

第二类:单顺子,双顺子,三顺子

我们发现,如果只按照第一类的方式打出,当每一种牌(有一张的,有两张的,有三张的,有四张的)的数量一定时,最少的出牌步数是一定的。所以我们考虑把这个先预处理出来,然后搜索顺子的情况。

设\(F[i][j][k][l]\)表示单张\(i\)张,对子\(j\)对,三张的\(k\)组,炸弹\(l\)组时的最少步数。我们有下面的转移方程:(注意,都要在有意义的情况下转移,比如说\(i,j,k,l\)不能出现负值

考虑单张
F[i][j][k][l]=min(F[i][j][k][l],F[i-1][j][k][l]+1);//打出一个单牌
考虑对子
F[i][j][k][l]=min(F[i][j][k][l],F[i][j-1][k][l]+1);//打出一个对子
考虑三张
F[i][j][k][l]=min(F[i][j][k][l],F[i][j][k-1][l]+1);//打出三张牌
F[i][j][k][l]=min(F[i][j][k][l],F[i-1][j][k-1][l]+1);//打出三带一
F[i][j][k][l]=min(F[i][j][k][l],F[i][j-1][k-1][l]+1);//打出三带二
考虑四张
F[i][j][k][l]=min(F[i][j][k][l],F[i][j][k][l-1]+1);//打出四张牌
F[i][j][k][l]=min(F[i][j][k][l],F[i-2][j][k][l-1]+1);//打出四带两张单牌
F[i][j][k][l]=min(F[i][j][k][l],F[i][j-2][k][l-1]+1);//打出四带两对牌

然后我们搜索顺子的情况。可以作为顺子的是3~A,所以为了方便,我们在输入的时候把1变成14。注意,顺子可以不打完,双顺子可以拆成单顺子,三顺子可以拆成单顺子或双顺子。最后统计最优解。

另外需要注意的是,两张王既可以看作两张单牌,也可以看作一对子。

本题加强版:http://www.cnblogs.com/SYCstudio/p/7628971.html

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; const int maxN=25;
const int Shunzi[4]={0,5,3,2};//i顺子至少需要多少张牌
const int inf=2147483647; int n;
int Card[maxN];//记录每一种牌剩余的数量
int F[maxN][maxN][maxN][maxN];
int Ans; void init();
void dfs(int step);
int now_step(int x1,int x2,int x3,int x4);//计算当前如果只按照第一类方式打出牌的最少步数,x1~x4分别是1张~4张牌的数量 int main()
{
int T;
scanf("%d%d",&T,&n);
init();
while (T--)//多组数据
{
memset(Card,0,sizeof(Card));
Ans=n;
for (int i=1;i<=n;i++)//输入
{
int a,b;
scanf("%d%d",&a,&b);
if (a==0)//0是王
Card[0]++;
else
if (a==1)//将'A'单独拿出来,变成14,方便处理顺子
Card[14]++;
else
Card[a]++;
}
dfs(0);
printf("%d\n",Ans);
}
return 0;
} void init()//计算出F
{
F[0][0][0][0]=0;
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
for (int k=0;k<=n;k++)
for (int l=0;l<=n;l++)
{
F[i][j][k][l]=i+j+k+l;
if (i+2*j+3*k+4*l<=n)
{
if (i!=0)//一张牌
F[i][j][k][l]=min(F[i][j][k][l],F[i-1][j][k][l]+1);//打出一个单牌
if (j!=0)//双牌
F[i][j][k][l]=min(F[i][j][k][l],F[i][j-1][k][l]+1);//打出一个对子
if (k!=0)//三张牌
{
F[i][j][k][l]=min(F[i][j][k][l],F[i][j][k-1][l]+1);//打出三张牌
if (i!=0)
F[i][j][k][l]=min(F[i][j][k][l],F[i-1][j][k-1][l]+1);//打出三带一
if (j!=0)
F[i][j][k][l]=min(F[i][j][k][l],F[i][j-1][k-1][l]+1);//打出三带二
}
if (l!=0)//四张牌
{
F[i][j][k][l]=min(F[i][j][k][l],F[i][j][k][l-1]+1);//打出四张牌
if (i>=2)
F[i][j][k][l]=min(F[i][j][k][l],F[i-2][j][k][l-1]+1);//打出四带两张单牌
if (j>=2)
F[i][j][k][l]=min(F[i][j][k][l],F[i][j-2][k][l-1]+1);//打出四带两对牌
}
//printf("(%d,%d,%d,%d) %d\n",i,j,k,l,F[i][j][k][l]);
}
}
return;
} void dfs(int step)//搜索顺子,step表示当前打出多少个顺子
{
if (step>Ans)//最优性剪枝
return;
int Cnt[maxN];
memset(Cnt,0,sizeof(Cnt));//记录有1张~4张的牌分别有多少种
for (int i=2;i<=14;i++)//注意这里要统计2
Cnt[Card[i]]++;
Ans=min(Ans,step+now_step(Cnt[1],Cnt[2],Cnt[3],Cnt[4]));//计算当前剩余的都按照第一类方式打出的最少步数
for (int k=1;k<=3;k++)//枚举顺子or双顺子or三顺子
{
for (int i=3;i<=14;i++)//注意这里从3开始
{
int pos;
for (pos=i;(pos<=14)&&(Card[pos]>=k);pos++)
{
Card[pos]=Card[pos]-k;//减去顺子
if (pos-i+1>=Shunzi[k])
dfs(step+1);//当满足构成一个顺子时,就可以先打出去
}
for (pos=pos-1;pos>=i;pos--)//还原
Card[pos]=Card[pos]+k;
}
}
return;
} int now_step(int x1,int x2,int x3,int x4)
{
if (Card[0]==0)
return F[x1][x2][x3][x4];//没有王
if (Card[0]==1)
return F[x1+1][x2][x3][x4];//只有一个王
if (Card[0]==2)
return min(F[x1+2][x2][x3][x4],F[x1][x2][x3][x4]+1);//将两张王看作两张单牌or一对牌
}

Luogu 2668 NOIP 2015 斗地主(搜索,动态规划)的更多相关文章

  1. 洛谷 P2668 & P2540 [ noip 2015 ] 斗地主 —— 搜索+贪心

    题目:https://www.luogu.org/problemnew/show/P2668   https://www.luogu.org/problemnew/show/P2540 首先,如果没有 ...

  2. Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)

    Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...

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

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

  4. [NOIp 2015]斗地主

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

  5. [BZOJ 4325][NOIP 2015] 斗地主

    一道防AK好题 4325: NOIP2015 斗地主 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 820  Solved: 560[Submit] ...

  6. [NOIP 2015] 斗地主 landlord

    想起几个月之前的 noip2015-只会瞎搞-这道题骗了 30 分.T T 题目 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的 A 到 K 加上大小王的共 54 张牌 ...

  7. noip 2015 斗地主 大爆搜!!!

    反正肯定是大模拟 但是每一个可以出的牌都搜一定不是最优的 考虑最特殊的出牌方案:顺子(单,对,三) 每一种方案再加上暴力贪心打出剩下的牌的步数 #include<cstdio> #incl ...

  8. Luogu 1979 NOIP 2013 华容道(搜索,最短路径)

    Luogu 1979 NOIP 2013 华容道(搜索,最短路径) Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面 ...

  9. NOIP 2015

    Prob.1 2015 神奇的幻方 模拟就好了.(这不是noip2017的初赛题么.)代码: #include<cstdio> #include<cstring> #inclu ...

随机推荐

  1. 理解标准盒模型和怪异模式&box-sizing属性

    盒子模型 主要有两种,w3c标准盒模型,IE下的怪异盒模型,其实还有就是弹性盒模型(上篇文章我们用他很好的解决了对齐问题) DTD规范 盒模型分为:标准w3c盒模型.IE盒模型.以及css中的伸缩盒模 ...

  2. NTP服务部署和测试

    1. 概述2. 部署3. 配置4. 客户端配置4.1 客户端安装ntpdate4.2 同步设置 1. 概述 本篇博客主要记录如何部署一台NTP服务器,用于内网时间同步. 时间服务器对于集群内部节点之间 ...

  3. Python 工程管理及 virtualenv 的迁移

    virtualenv 是管理 python 工程的利器,它可以很好的帮你维护项目中的依赖,使用 virtualenv,还能保持 global 库的干净.不会被不同项目中的第三方库所污染. virtua ...

  4. 全景3d

    Three.js Tour.js Run.js 3D Css3 酷家乐:https://www.kujiale.com/ 爱空间:http://bj.ikongjian.com/?utm_source ...

  5. 第三个Sprint ------第四天

    出题代码 package com.app.senior_calculator; import java.io.Serializable; public class Question implement ...

  6. Sprint 冲刺第三阶段第一天

    1.今晚我在整理之前的代码,检查细节,然后发现游戏要返回上一界面竟然出现了问题“项目停止运行”,仔细检查没办法解决,后来百度可能是因为修改了之前文件的名字,可在AndroidManifest.xml中 ...

  7. Online Resource Mapping for SDN Network Hypervisors using Machine Learning

    发表时间:2016 一些定义: self-configuring networks: FlowVisor: FlowVisor是建立在OpenFlow之上的网络虚拟化工具,它可以将物理网络划分成多个逻 ...

  8. 『编程题全队』Beta 阶段冲刺博客四

    1.提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID) (1) 昨天已完成的工作 孙志威: 1.新增添加提醒事项的按钮 2.添加了新建提醒框 3.测试了新的SubTask思 ...

  9. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stu' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stu' defined ...

  10. MySQLi面向对象实践--insert、update、delete

    执行insert <?php $mysqli = new Mysqli(); $mysqli->connect("localhost","root" ...