基本套路选讲

本文深入探讨了一种基于深度优先搜索(DFS)的扑克牌游戏算法,详细解释了如何通过DFS实现完全搜索,以找到最优的出牌策略。文章涵盖了单顺子、双顺子、三顺子等出牌方式的搜索策略,并讨论了如何优化搜索过程以提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.luogu.org/problemnew/show/P1008

https://www.luogu.org/problemnew/show/P2668
这道题明显就是一个大暴力,但是考场上碰到这种题确实让人伤脑筋,
如何在考场上稳稳地拿下这100分呢?
首先,为了进行完全的搜索,这题应用DFS的结构,
而不是贪心选择某种出牌方式。然后我们应先分析搜索的方法。

在DFS中我们先考虑不带牌的出法。即单顺子,双顺子,三顺子。

三带一、三带二可以看做是特殊的三张牌;

四带二可以看做是特殊的炸弹。

通过归纳,剩下的出牌方法就只有单排,对子和王炸了。

所以在DFS的单层中,程序需要做:
搜索单顺子,双顺子,三顺子
搜索三张牌,炸弹
搜索剩下的单排,对子,王炸
这样写的话可能只能通过60%~80%的数据。考虑优化
三张牌和炸弹带的牌可以最后在剩下的单排,对子中去除。
而不用在搜索三张牌,炸弹时进行搜索。

https://www.luogu.org/problemnew/show/P2540

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
#define INF 2147483647
using namespace std;
struct sth
{
    int l[20];
    int ld,zd,w;
    bool operator ==(const sth y)const
    {
        if (ld!=y.ld) return false;
        if (zd!=y.zd) return false;
        if (w!=y.w) return false;
        for (int i=0;i<20;i++)
            if (l[i]!=y.l[i]) return false;
        return true; 
    }
}p,debug;
    int t,n,i,j,x,y,ans;
    int w,bs,sm;
bool cl(sth s)
{
    for (int k=3;k<=15;k++)
        if (s.l[k]>0) return false;
    return true;
}
void make(sth s,int step)
{
    if (cl(s)) 
    {
        step+=bool(s.w);
        if (step<ans) ans=step;
        return;
    }
    int k,l,m,h;
    sth f=s;
    for (k=3;k<=10;k++)
    {
        l=0;
        for (m=k;m<=14;m++)
        {
            if (f.l[m]>0) l++; else break;
            if (l>=5)
            {
                for (h=k;h<=m;h++)
                    f.l[h]--;
                make(f,step+1);
                f=s;
            }
        }
    }
    for (k=3;k<=12;k++)
    {
        l=0;
        for (m=k;m<=14;m++)
        {
            if (f.l[m]>1) l++; else break;
            if (l>=3)
            {
                for (h=k;h<=m;h++)
                    f.l[h]-=2;
                make(f,step+1);
                f=s;
            }
        }
    }
    for (k=3;k<=13;k++)
    {
        l=0;
        for (m=k;m<=14;m++)
        {
            if (f.l[m]>2) l++; else break;
            if (l>=2)
            {
                for (h=k;h<=m;h++)
                    f.l[h]-=3;
                make(f,step+1);
                f=s;
            }
        }
    }
    for (k=3;k<=15;k++)
    {
        if (f.l[k]>2)
        {
            f.l[k]-=3;
            f.ld++;
            make(f,step+1);
            f=s;
        }
    }
    for (k=3;k<=15;k++)
    {
        if (f.l[k]>3)
        {
            f.l[k]-=4;
            f.zd++;
            make(f,step+1);
            f=s;
        }
    }
    int dan=0,dui=0;
    for (k=3;k<=15;k++)
    switch(f.l[k])
    {
        case 1:dan++;break;
        case 2:dui++;break;
        case 3:dan++;dui++;break;
        case 4:dui+=2;break;
    }
    if (f.w) dan+=f.w;
    while (f.zd>0 && (dan>1||dui>0))
    {
        if (dui>1) dui-=2;
        else if (dan>1) dan-=2;
        else if (dui==1) dui-=1;
        f.zd--;
    }
    dan+=dui;
    while (f.ld>0&&dan>0)
    {
        f.ld--;
        dan--;
    }
    if (dan>=f.w) dan-=f.w; else f.w=0;
    for (k=3;k<=15;k++)
        f.l[k]=0;
    make(f,step+dan);
}
void init()
{
    debug.l[3]=1;
    debug.l[11]=1;
    debug.w=2;
    debug.l[12]=2;
    debug.ld=3;
    debug.zd=1;
}
int main()
{
//    init();
    scanf("%d%d",&t,&n);
    for (i=1;i<=t;i++)
    {
        memset(p.l,0,sizeof(p.l));
        w=0;
        for (j=1;j<=n;j++)
        {
            scanf("%d%d",&x,&y);
            if (x==1||x==2) x+=13;
            if (x==0) w++;
            else p.l[x]++;
        }
        p.w=w;
        ans=n;
        make(p,0);
        printf("%d\n",ans);
    }
    return 0;
}

前缀和  pre[i]=pre[i-1]+a[i] 
二维前缀和 
    pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j]
    pre[x2][y2]-pre[x1-1][y2]-pre[x2][y1-1]+pre[x1-1][y1-1]
    
    x1,y1
          
          
          
               x2,y2


https://www.luogu.org/problemnew/show/P3417    
 

第i个动作的第j位向后的最近一个数字k的位置 
if k == a[i][j][k+1]:
    suf[i][j][k]=k+1
else:
    suf[i][j][k]=suf[i][j][k+1]


    
 

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值