4325. 【NOIP2015提高组Day1】斗地主
https://jzoj.net/senior/#main/show/4325
15年提高组的题,看到标题我吓了一跳,但细细分析来,还是可以做的。
过流程(题目描述):
大致是说给你一些牌,按照上述出牌方式,最少几步可以出完所有牌。
一开始就想到了很平常的方法——dfs,但我们发现直接暴力会T,于是,观察数据:n是固定的,所以这题会有很多状态是一样的,我们便自然的想到了预处理。
首先看,除顺子外,其他出牌方式对点数都没有要求,只对数量有要求,所以大致的思路就是先预处理没有顺子的情况的出牌步数,然后暴力求顺子的状况,O(1)求解。
我们设f[i][j][k][l]表示还剩i种牌有4张,j种牌有3张,k种牌有2张,l种牌有1张的最小出牌步数。
于是就有除顺子外的9种转移:
int did(int a,int b,int c,int d)
{
int ss=a+b+c+d;
if (d>=1)
ss=min(ss,f[a][b][c][d-1]);
if (b>=1 && c>=1)
ss=min(ss,f[a][b-1][c-1][d]);
if (b>=1 && d>=1)
ss=min(ss,f[a][b-1][c][d-1]);
if (c>=1)
ss=min(ss,f[a][b][c-1][d]);
if (b>=1)
ss=min(ss,f[a][b-1][c][d]);
if (a>=1)
ss=min(ss,f[a-1][b][c][d]);
if (a>=1 && d>=2)
ss=min(ss,f[a-1][b][c][d-2]);
if (a>=1 && c>=2)
ss=min(ss,f[a-1][b][c-2][d]);
if (a>=1 && c>=1)
ss=min(ss,f[a-1][b][c-1][d]);
}
......
{
f[0][0][0][0]=0;
for (i=0;i<=n;i++)
for (j=0;j<=n;j++)
for (k=0;k<=n;k++)
for (l=0;l<=n;l++)
f[i][j][k][l]=min(did(i,j,k,l)+1,f[i][j][k][l]);
}
在此之后,我们可以递归1~3顺子的情况,每一种状态更新答案即可。
本文解析了NOIP2015提高组Day1的“斗地主”题目,通过预处理不同牌型组合的最优出牌策略,采用深度优先搜索(DFS)方法,并结合顺子情况的递归求解,实现了复杂牌局的高效求解。

756

被折叠的 条评论
为什么被折叠?



