acwing提高——迭代加深+双向dfs+IDA*

news2024/11/13 14:32:24

1.迭代加深

顾名思义说明迭代的层数逐渐加深,这样做法有点像bfs的做法层层突出,符合的题型是答案在层数较低的那一层里

加成序列

题目https://www.acwing.com/problem/content/description/172/

#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n;
int path[N];
bool dfs(int u,int depth)//第一个是元素个数,第二个是当前的深度
{
    if(u>depth) return  false;//假如元素大于深度,说明不可能了
    if(path[u-1]==n) return true;//假如元素个数达到深度,且最后一个是n,则说明符合条件
    bool st[N]={0};//用来标记那个数已经枚举过
    for(int i=u-1;i>=0;i--)//枚举前u个数,两两可以相加,相当于组合数
        for(int j=i;j>=0;j--)
        {
           int s=path[i]+path[j];//获取这两个数的值
           if(st[s]||s>n||s<=path[u-1]) continue;//假如已经枚举过或者和大于n或者不符合后一个数比前一个数小,则跳过
            st[s]=true;//标记这个数已经用过
            path[u]=s;//这个数放进数组里
           if(dfs(u+1,depth)) return true;//继续搜索下一个数
        }
    return false;
}
int main()
{
    path[0]=1;//规定第一个数是1
   while(cin>>n,n)
   {
       int depth=1;//枚举深度,大概知道答案在比较近的一层,所以不枚举宽度
       while(!dfs(1,depth)) depth++;//假如这个深度不符合,则加1
       for(int i=0;i<depth;i++) cout<<path[i]<<' ';//输出答案
       puts("");
   }
   return 0;
}

2.双向dfs

顾名思义就是分两段dfs,搜索前半段与后半段

送礼物

第一种使用了unique函数判重可能会超时 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int n,k;
int cnt=1;
ll w[N],m,weight[1<<25],ans;
void dfs1(int u,ll s)
{
    if(s>m) return;//假如已经大于了,则直接返回
    if(u==k)//假如搜到了最后一个
    {
        weight[cnt++]=s;//把这个值放进数组里来
        return;//这里不能少
    }
    dfs1(u+1,s);//假如不选这个数
    if(s+w[u]<=m) dfs1(u+1,s+w[u]);//假如满足条件选这个数
}
void dfs2(int u,ll s)
{
   if(s>m) return;//假如已经大于了,则直接返回
   if(u==n)//假如搜到了最后一个
   {
       //下面二分有左边界,因为找刚好小于m的最大数
      int l=0,r=cnt-1;
      while(l<r)
      {
          int mid=l+r+1>>1;
          if(weight[mid]+s<=m) l=mid;
          else r=mid-1;
      }
     ans=max(ans,s+weight[l]);//更新一下答案
     return;//这里不能少
   }
    dfs2(u+1,s);//假如不选这个数
    if(s+w[u]<=m) dfs2(u+1,s+w[u]);//假如符合条件选这个数
}
int main()
{
    cin>>m>>n;
    for(int i=0;i<n;i++) cin>>w[i];
    //从大到小排序
    sort(w,w+n);
    reverse(w,w+n);
    k=n/2+1;//对半分开搜索
    dfs1(0,0);//搜索前半段,打表出来存进数组里头
    //去重
    sort(weight,weight+cnt);
    cnt=unique(weight,weight+cnt)-weight;
    dfs2(k,0);//搜索后半段
    cout<<ans<<endl;
   return 0;
}

第二种手写判重 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int n,k;
int cnt=1;
ll w[N],m,weight[1<<25],ans;
void dfs1(int u,ll s)
{
    if(s>m) return;//假如已经大于了,则直接返回
    if(u==k)//假如搜到了最后一个
    {
        weight[cnt++]=s;//把这个值放进数组里来
        return;//这里不能少
    }
    dfs1(u+1,s);//假如不选这个数
    if(s+w[u]<=m) dfs1(u+1,s+w[u]);//假如满足条件选这个数
}
void dfs2(int u,ll s)
{
   if(s>m) return;//假如已经大于了,则直接返回
   if(u==n)//假如搜到了最后一个
   {
       //下面二分有左边界,因为找刚好小于m的最大数
      int l=0,r=cnt-1;
      while(l<r)
      {
          int mid=l+r+1>>1;
          if(weight[mid]+s<=m) l=mid;
          else r=mid-1;
      }
     ans=max(ans,s+weight[l]);//更新一下答案
     return;//这里不能少
   }
    dfs2(u+1,s);//假如不选这个数
    if(s+w[u]<=m) dfs2(u+1,s+w[u]);//假如符合条件选这个数
}
int main()
{
    cin>>m>>n;
    for(int i=0;i<n;i++) cin>>w[i];
    //从大到小排序
    sort(w,w+n);
    reverse(w,w+n);
    k=n/2+1;//对半分开搜索
    dfs1(0,0);//搜索前半段,打表出来存进数组里头
    
    // 判重 去重
    int t = 1;
    for (int i = 1; i < cnt; i++)
        if (weight[i] != weight[i - 1])
            weight[t++] = weight[i];
    cnt = t;

    dfs2(k,0);//搜索后半段
    cout<<ans<<endl;
   return 0;
}

3.IDA*

找估计函数,在枚举步数,用估计函数+当前步数来剪枝,大大提高效率,前提是答案的层数小

 1.排书

题目https://www.acwing.com/problem/content/182/

#include<bits/stdc++.h>
using namespace std;
const int N=20;
int n;
int q[N],w[5][N];
int f()//用来计算估计函数
{
    int totol=0;//算位置不符合的总个数
    for(int i=0;i<n-1;i++)
      if(q[i]!=q[i+1]-1)
         totol++;
    return (totol+2)/3;//因为每次交换能更改三个位置的后缀,我们算他改的都是正确的则就除以三,但是实际肯定是小了的
}
bool dfs(int depth,int max_depth)//depth是当前已执行的步数,max_depth是最大步数
{
    if(f()+depth>max_depth) return false;//假如当前步数加上估计函数大于最大步数了,说明不符合
    if(f()==0) return true;//假如估计函数为0,也就是正确答案了,则直接返回true
    for(int len=1;len<=n;len++)//枚举需要更改的长度
        for(int l=0;l+len-1<n;l++)//枚举左边界
        {
            int r=l+len-1;//右边界
            for(int k=r+1;k<n;k++)//枚举需要跟右边那个位置交换
            {
                memcpy(w[depth],q,sizeof q);//把上一层的状态复制过来
                int x=l;
                //下面进行这一段跟右边的位置交换
                for(int y=r+1;y<=k;y++,x++) q[x]=w[depth][y];
                for(int y=l;y<=r;y++,x++) q[x]=w[depth][y];
                //进行下一步,假如下一步可以符合答案,则链式返回true
                if(dfs(depth+1,max_depth)) return true;
                memcpy(q,w[depth],sizeof q);//把更改后的这一层q复制到w这一层中,供下一层使用
            }
        }
    return false;//反之返回失败
}
int main()
{
   int T;
   cin>>T;
   while(T--)
   {
       cin>>n;
       for(int i=0;i<n;i++) cin>>q[i];
       int depth=0;//枚举所用的步数
       while(depth<5&&!dfs(0,depth)) depth++;//假如所用步数不能排好书,则步数++
       if(depth<5) cout<<depth<<endl;
       else puts("5 or more");
   }
   return 0;
}

 2.回转游戏

题目 https://www.acwing.com/problem/content/183/

#include<bits/stdc++.h>
using namespace std;
const int N=24;
int n;
int q[N],path[110];
//分别为八个方向的位置
int op[8][7]=
{
    {0,2,6,11,15,20,22},
    {1,3,8,12,17,21,23},
    {10,9,8,7,6,5,4},
    {19,18,17,16,15,14,13},
    {23,21,17,12,8,3,1},
    {22,20,15,11,6,2,0},
    {13,14,15,16,17,18,19},
    {4,5,6,7,8,9,10}
};
int unop[8]={5,4,7,6,1,0,3,2};//八个方向的反操作,避免往上拉了,又往下拉,等于没操作
int cenctr[8]={6,7,8,11,12,15,16,17};//中心的8个位置
int f()//算估计函数
{
    static int temp[4];//静态数组节省空间
    memset(temp,0,sizeof temp);//清空
    for(int i=0;i<8;i++) temp[q[cenctr[i]]]++;//记录中间那个数出现的最多
    int m=0;
    for(int i=1;i<=3;i++) m=max(m,temp[i]);//求一下出现最多的数的个数
    return 8-m;//返回最少需要操作的次数,也就是8-m
}
void operate(int x)//进行把数组第一个往上拉去最后一个,其他往前一个位置的操作
{
    int t=q[op[x][0]];
    for(int i=0;i<6;i++) q[op[x][i]]=q[op[x][i+1]];
    q[op[x][6]]=t;
}
bool dfs(int depth,int max_depth,int last)//depth是当前步数,max_depth是最大步数,last是上一步的操作
{
    if(depth+f()>max_depth) return false;//假如估计函数+目前步数已经大于最大步数了,则返回false
    if(f()==0) return true;//假如已经排好了,则返回true
    for(int i=0;i<8;i++)//枚举8个操作
        if(unop[i]!=last)//返回操作了上又操作下,等于没操作
        {
           operate(i);//操作i
           path[depth]=i;//把当前路径标记为i操作的
           if(dfs(depth+1,max_depth,i)) return true;//假如下一步操作是true,则返回true
           operate(unop[i]);//恢复现场,也就是反向操作一下
        }
  return false;//找不到合法答案
}
int main()
{
  while(cin>>q[0],q[0])
  {
      for(int i=1;i<N;i++) cin>>q[i];
      int depth=0;//枚举需要走的步数
      while(!dfs(0,depth,-1)) depth++;//假如改步数不符合,则步数++
      if(!depth) printf("No moves needed");
      else
      {
          for(int i=0;i<depth;i++) printf("%c",path[i]+'A');//输出路径
      }
      printf("\n%d\n",q[6]);//输出中心的数字
  }
   return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口测试系列之 —— 前端交互测试和后端逻辑测试

01 前端交互测试 前端页面与后端代码之间的交互测试&#xff0c;可以理解为接口功能测试的一个子集。 测试准备 在进行交互测试前&#xff0c;首先要对前端功能有明确的认知&#xff0c;能够明确区分&#xff1a; 什么功能属于前端页面逻辑功能 什么功能又属于前端与后端…

路径规划算法:基于树种优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于树种优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于树种优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法树种…

JMeter快速入门指南:轻松掌握基本操作

Jmeter 介绍 Jmeter 是一款使用Java开发的&#xff0c;开源免费的&#xff0c;测试工具&#xff0c; 主要用来做功能测试和性能测试&#xff08;压力测试/负载测试&#xff09;. 而且用Jmeter 来测试 Restful API, 非常好用。 2023Jmeter性能测试项目实战教程&#xff0c;十…

ffmpeg下载及ffmpy3安装使用

ffmpeg下载及ffmpy3安装使用 1.下载ffmpeg 进入网址&#xff1a;https://www.gyan.dev/ffmpeg/builds/ 在release builds中下载ffmpeg-release-full.7z 下载好后解压到自己想存放的目录&#xff0c;例如&#xff1a;D:\Tool\ffmpeg-6.0-full_build 2.配置环境变量 右键此电…

《最新出炉》Python+Playwright自动化测试-1-环境准备与搭建

一.简介 有很多人问能不能介绍一下Playwright这款自动化神器的相关知识&#xff0c;现在网上的资料太少了。其实在各大博客和公众号也看到过其相关的介绍和讲解。要不就是不全面、不系统&#xff0c;要不就是系统全面但是人家是收费的。当然了接下来也可能介绍的不全面或者不系…

什么是压力测试?什么是负载测试?这两个区别是什么?

前言 之前给一个客户做项目时&#xff0c;由于自己对性能测试了解并不深&#xff0c;搞不懂压力测试和负载测试的区别&#xff0c;导致后面还是由负责性能测试的同事来处理&#xff0c;他跟我说了很多关于压力测试和负载测试的区别&#xff0c;现在我总结如下。 压力测试 压…

解决node上传文件乱码问题终极方案

问题描述 今天在菜鸟教程学习node上传文件时遇到了一个中文乱码的问题&#xff0c;文件名包含中文就会显示乱码&#xff0c;上传到服务器的文件名也是乱码。试了两个方法都不行&#xff0c;最后还是问了万能的度娘才解决。 我做了一个非常简单的上传文件的界面&#xff0c; …

Java SE(十二)之多线程

文章目录 概述1.进程&线程2.并行&并发 线程创建方式1.第一种&#xff1a;继承Thread类2.第二种&#xff1a;实现Runnable接口3.Callable、FutureTask接口4.线程创建的三种方式对比 Thread常用方法1.构造器2.设置和获取线程名称3.线程调度4.线程控制5.线程生命周期 线程…

静态路由和默认路由的工作原理

目录 静态路由 静态路由配置 默认&#xff08;缺省&#xff09;路由 路由的高级特性 1&#xff0c;递归路由 2&#xff0c;等价路由 3&#xff0c;浮动路由 4&#xff0c;路由汇总 环路问题&#xff1a; 解决方法&#xff1a; 静态路由 在路由器手动添加路由条目 静…

基于深度学习的高精度浣熊检测识别系统(PyTorch+Pyside6+模型)

摘要&#xff1a;基于深度学习的高精度浣熊检测&#xff08;水牛、犀牛、斑马和大象&#xff09;识别系统可用于日常生活中或野外来检测与定位浣熊目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的浣熊目标检测识别&#xff0c;另外支持结果可视化与图片或视…

Spring Boot 集成支付宝、微信等支付平台API

Spring Boot 集成支付宝、微信等支付平台API 在现代的 Web 应用程序开发中&#xff0c;与第三方 API 的集成是非常常见的需求。例如&#xff0c;支付宝、微信等支付平台的支付接口、短信验证码的发送接口、邮件发送接口等。Spring Boot 提供了许多便捷的方式来集成这些第三方 …

Python实战基础17-包

1、pip的安装配置 1.1 pip命令的使用 在安装python时&#xff0c;同时还会安装pip软件&#xff0c;它是python的包管理工具&#xff0c;可以用来查找、下载、安装和卸载python的第三方资源包。 1.2 配置pip 可以直接在终端输入pip命令&#xff0c;如果出错可能会有两个原因…

接口自动化测试实战:JMeter+Ant+Jenkins+钉钉机器人群通知完美结合

目录 前言 一、本地JAVA环境安装配置&#xff0c;安装JAVA8和JAVA17 二、安装和配置Jmeter 三、安装和配置ant 四、jmeter ant配置 五、jenkins安装和配置持续构建项目 文末福利 前言 搭建jmeterantjenkins环境有些前提条件&#xff0c;那就是要先配置好java环境&#…

OS-内存管理-4种内存管理方式(连续分配,页式,段式,段页)。

一&#xff0c;内存管理四种方式。 二&#xff0c;连续分配管理方式。 连续分配方式&#xff1a;为用户分配连续的内存空间。 1.单一连续分配方式 2.固定分区分配方式 3.动态分区分配方式 4.三种连续分配方式的对比。 三&#xff0c;基于页式存储管理。 1.页式 为进一步提高…

【来不及刷题之】32、二分搜索(寻找数,寻找左右边界)

1. 基础二分搜索&#xff1a;寻找一个数 一道很基础的题目&#xff0c;主要注意一下循环条件是 left<right 即可 class Solution {public int search(int[] nums, int target) {int left0;int rightnums.length-1;while(left<right){int midleft(right-left)/2;if(nums…

第二十一章行为性模式—访问者模式

文章目录 访问者模式解决的问题结构实例存在的问题使用场景 拓展动态分派静态分派双分派 行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。行为型模…

华为OD机试真题B卷 Java 实现【箱子之形摆放】,附详细解题思路

一、题目描述 要求将一批箱子按从上到下以‘之’字形的顺序摆放在宽度为 n 的空地上&#xff0c;输出箱子的摆放位置&#xff0c;例如&#xff1a;箱子ABCDEFG&#xff0c;空地宽为3。 摆放效果如下图&#xff1a; 则输出结果为&#xff1a; AFG BE CD 二、输入描述 一行…

智能语音交互流程

引言 用该文来讲解语音全流程涉及到的技术&#xff0c;整体语音涉及的交互流程如下图&#xff1a; Part1 唤醒 语音唤醒指的是通过预设的关键词即可将智能硬件从休眠状态唤醒&#xff0c;来执行相应操作。 1.1 交互模式 传统模式 唤醒方式&#xff1a;先唤醒设备&#xff…

重学数据结构与算法

学习数据结构与算法的目的&#xff1a; 优化时间复杂度与空间复杂度 优化时间复杂度与空间复杂度 优化时间复杂度与空间复杂度 教程总纲&#xff1a; 暴力解法(模拟)、算法优化(递归/二分/排序/DP)、时刻转换(数据结构) 1.时间复杂度的核心方法论2.增删查——选取数据结构的基…

MySQL_9 事务机制与隔离机制

目录 一、事务概述 1.定义 : 2.事务和锁 : 二、事务操作 1.MySQL控制台事务的基本操作 : 2.代码演示 : 3.注意事项 : 三、事务的“ACID”特性 : 四、隔离机制 1.介绍 : 2.分类 : 3.常用指令 : 一、事务概述 1.定义 : 事务用于保证数据的一致性&#xff0c;它由一…