P2540 [NOIP2015 提高组] 斗地主加强版题解
题目描述
给出n张牌,求出打光n牌的最少次数,详情请看题面
分析
考虑出牌是我们要分两种情况:顺子,散牌。
应为只有顺子要考虑点数,散牌不需要。
顺子
爆搜即可。
Q:有人可能会问直接求不香吗?
A:直接算最长的并不是最优解。
eg.
有点数为:3,4,5,6,6,7,7,8,9,10
那最长的会多两个单,但我们可以{3,4,5,6,7},{6,7,8,9,10}
散牌
dp即可
设dp[a][b][c][d][e]为a张单牌,b张对,c对三连,d个炸弹,e张王的状态。
eg.
单张可以从dp[a-1][b][c][d][e]转移过来
三带一可以从dp[a-1][b][c-1][d][e]转移过来
代码
是不是挺简单的。
前方高能码风
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n,a,b,ans;
int p[20],dp[20][20][20][20][5],cnt[10],st[10]={0,5,3,2};
void init()
{
memset(dp,0x3f,sizeof(dp));
dp[0][0][0][0][0]=0;
for(int d=0;d<=15;d++)
for(int c=0;c<=15;c++)
for(int a=0;a<=15;a++)
for(int b=0;b<=15;b++)
for(int e=0;e<=2;e++)
{
int minn=0x3f;
if(a>0)minn=min(minn,dp[a-1][b][c][d][e]+1);
if(b>0)minn=min(minn,dp[a][b-1][c][d][e]+1);
if(c>0)minn=min(minn,dp[a][b][c-1][d][e]+1);
if(d>0)minn=min(minn,dp[a][b][c][d-1][e]+1);
if(e>0)minn=min(minn,dp[a][b][c][d][e-1]+1);
if(b>0&&d>0)minn=min(minn,dp[a][b-1][c][d-1][e]+1);
if(d>0&&e>1)minn=min(minn,dp[a][b][c][d-1][e-2]+1);
if(b>1&&d>0)minn=min(minn,dp[a][b-2][c][d-1][e]+1);
if(d>1)minn=min(minn,dp[a][b][c][d-2][e]+1);
if(a>1&&d>0)minn=min(minn,dp[a-2][b][c][d-1][e]+1);
if(a>0&&d>0&&e>0)minn=min(minn,dp[a-1][b][c][d-1][e-1]+1);
if(c>0&&e>0)minn=min(minn,dp[a][b][c-1][d][e-1]+1);
if(a>0&&c>0)minn=min(minn,dp[a-1][b][c-1][d][e]+1);
if(b>0&&c>0)minn=min(minn,dp[a][b-1][c-1][d][e]+1);
if(c>0)minn=min(minn,dp[a+1][b+1][c-1][d][e]);
if(d>0)minn=min(minn,dp[a+1][b][c+1][d-1][e]);
if(e>1)minn=min(minn,dp[a][b][c][d][e-2]+1);
dp[a][b][c][d][e]=min(dp[a][b][c][d][e],minn);
}
}
void dfs(int x)
{
if(x>=ans)return ;
for(int k=1;k<=3;k++)
for(int i=1;i<=12;i++)
{
int l=0;
while(i+l<=12&&p[i+l]>=k)l++;
for(int j=l;j>=st[k];j--)
{
for(int t=i;t<=i+j-1;t++)p[t]-=k;
dfs(x+1);
for(int t=i;t<=i+j-1;t++)p[t]+=k;
}
}
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=13;i++)cnt[p[i]]++;
cnt[5]=p[14];
ans=min(ans,x+dp[cnt[1]][cnt[2]][cnt[3]][cnt[4]][cnt[5]]);
}
int main()
{
scanf("%d%d",&t,&n);
init();
while(t--)
{
ans=n;
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
if(a==0)p[14]++;
else if(a==1)p[12]++;
else if(a==2)p[13]++;
else p[a-2]++;
}
dfs(0);
printf("%d\n",ans);
}
return 0;
}
本文作者:Gdfzlcx
本文链接:https://www.cnblogs.com/gdfzlcx/p/16639915.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步