DFS之搜索顺序与剪枝

news2024/9/22 15:35:05

搜索顺序:

1.https://www.acwing.com/problem/content/1119/

首先,我们考虑一个贪心:

假如说A的倒数K个字符恰好与B的前K个字符重合,那么我们就连接。

也就是说我们一旦匹配就直接相连而不是继续找更长的重合的一段子串。

因此,我们可以先预处理出任意两个字符串重叠的部分,接下来就是DFS了:

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int g[100][100];//i的尾与j的头重叠的最小长度
string w[100];
int u[1000];
int ans;
void dfs(string dd,int last){
    ans=max(ans,(int)dd.size());
    u[last]++;
    for(int i=1;i<=n;i++){
        if(g[last][i]&&u[i]<2){
            dfs(dd+w[i].substr(g[last][i]),i);
        }
    }
    u[last]--;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    char start;
    cin>>start;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            //if(i==j) continue;
            for(int k=1;k<min(w[i].size(),w[j].size());k++){
                if(w[i].substr(w[i].size()-k)==w[j].substr(0,k)){
                    g[i][j]=k;
                    break;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(w[i][0]==start){
            dfs(w[i],i);
        }
    }
    cout<<ans;
}

2.https://www.acwing.com/problem/content/1120/

首先,数据范围小,直接考虑爆搜。

那么选什么搜索顺序?我们按照每一个“桶”里放什么元素来DFS。

具体的,我们先看看第一个桶里放什么,当然存在某个时刻,第一个桶再也放不下所有东西了,于是我们就再开一个桶。

这里存在一个选择:当现在的桶还可以放东西时,是否还有必要再开一个桶?

答案是否定的,因为假如再开一桶,把那个东西放到上一个桶中一定也是合法的,因此答案不会更优。

同时注意我们选取东西不是DFS排列而是组合(因此规定从小到大)。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[1010];
int ans=20;
int group[20][20];
int gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}
int check(int u,int j,int cnt1){
    for(int i=1;i<=cnt1;i++){
        if(gcd(a[group[u][i]],a[j])!=1) return 0;
    }
    return 1;
}
int vis[100];
void dfs(int u,int cnt,int start,int cnt1){
    if(u>=ans) return;
    if(cnt==n){
        ans=u;
        return;
    }
    int f=-1;
    for(int i=start+1;i<=n;i++){
        if(vis[i]==0&&check(u,i,cnt1)){
            f=1;
            vis[i]=1;
            cnt1++;
            group[u][cnt1]=i;
            dfs(u,cnt+1,i,cnt1);
            cnt1--;
            vis[i]=0;
        }
    }
    if(f==-1){
        dfs(u+1,cnt,0,0);
    }
    
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    dfs(1,0,0,0);
    cout<<ans;
}

剪枝:

1.https://www.acwing.com/problem/content/167/

枚举每只猫放哪个车即可。

#include<bits/stdc++.h>
using namespace std;
int c[100],n,w;
int ans=20;
int sum[10010];
void dfs(int u,int k){
    if(k>=ans) return;
    if(u==n+1){
        ans=k;
        return;
    }
    for(int i=0;i<k;i++){
        if(sum[i]+c[u]<=w){
            sum[i]+=c[u];
            dfs(u+1,k);
            sum[i]-=c[u];
        }
    }
    sum[k]=c[u];
    dfs(u+1,k+1);
    sum[k]=0;
}
int main(){
    cin>>n>>w;
    for(int i=1;i<=n;i++) cin>>c[i];
    sort(c+1,c+n+1);
    reverse(c+1,c+n+1);
    dfs(1,0);
    cout<<ans<<endl;
}

2.https://www.acwing.com/problem/content/168/

总思路:随意选空格子,看是否可以填。

考虑剪枝:

1。优化搜索顺序:优先选限制多的

2.可行性剪枝:不能与行列以及九宫格重。

3.位运算加速:通过011100.....等九位01串来表示可行状态,求交集即可得到可行方案。

#include<bits/stdc++.h>
using namespace std;
const int N = 9, M = 1 << N;
int ones[M], cmap[M];
int row[N], col[N], cell[3][3];
char str[100];
void init()//一开始都可以选
{
    for (int i = 0; i < N; i ++ )
        row[i] = col[i] = (1 << N) - 1;

    for (int i = 0; i < 3; i ++ )
        for (int j = 0; j < 3; j ++ )
            cell[i][j] = (1 << N) - 1;
}

void draw(int x, int y, int t, bool is_set)
{
    if (is_set) str[x * N + y] = '1' + t;
    else str[x * N + y] = '.';
    int v = 1 << t;
    if (!is_set) v = -v;
    row[x] -= v;
    col[y] -= v;
    cell[x / 3][y / 3] -= v;
}

int lowbit(int x)
{
    return x & -x;
}

int get(int x, int y)
{
    return row[x] & col[y] & cell[x / 3][y / 3];
}

bool dfs(int cnt)
{
    if (!cnt) return true;

    int minv = 10;
    int x, y;
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            if (str[i * N + j] == '.')
            {
                int state = get(i, j);
                if (ones[state] < minv)
                {
                    minv = ones[state];
                    x = i, y = j;
                }
            }
//找到最优点
    int state = get(x, y);
    for (int i = state; i; i -= lowbit(i))
    {
        int t = cmap[lowbit(i)];
        draw(x, y, t, true);
        if (dfs(cnt - 1)) return true;
        draw(x, y, t, false);
    }

    return false;
}

int main()
{
    for (int i = 0; i < N; i ++ ) cmap[1 << i] = i;
    for (int i = 0; i < 1 << N; i ++ )
        for (int j = 0; j < N; j ++ )
            ones[i] += i >> j & 1;//处理i有多少1

    while (cin >> str, str[0] != 'e')
    {
        init();
        int cnt = 0;//空格子数量
        for (int i = 0, k = 0; i < N; i ++ )
            for (int j = 0; j < N; j ++, k ++ )
                if (str[k] != '.')
                {
                    int t = str[k] - '1';
                    draw(i, j, t, true);//进行跟新
                }
                else cnt ++ ;
        dfs(cnt);
        puts(str);
    }
}

3.https://www.acwing.com/problem/content/169/

整体思路:

先从小到大枚举木棒的长度,然后就是暴力DFS了。

考虑剪枝:

1.长度是sum的约数。

2.先枚举较长的木棍。

3.枚举组合数(下标从小到大)

4.木棒1失败,那么与它等长的也失败。

5.当前的第一个木棍失败,那么就直接回溯:

证明:假如3是某一个棒的第一个失败了,那么它一定存在在其他木棒中(假设4),那么木棒4中3的位置一定可以移到第一位,然后把棒4与3交换一下位置即可得出矛盾。

6.当前的最后一个木棍失败,那么就直接回溯:

证明:假如3是某一个棒的最后一个失败了,那么考虑把它放在其他木棒中(假设4),那么刚才那个木棒的填充最后一个的与放在4的那个交换一下一定也可,这也与前矛盾。

#include<bits/stdc++.h>
using namespace std;
const int N = 70;
int n;
int w[N];
int sum, length;
bool st[N];
bool dfs(int u, int cur, int start)//u:当前枚举的木棒cur:当前枚举的木棒的位置start:下标开始
{
    if (u * length == sum) return true;
    if (cur == length) return dfs(u + 1, 0, 0);
    for (int i = start; i < n; i ++ )
    {
        if (st[i] || cur + w[i] > length) continue;
        st[i] = true;
        if (dfs(u, cur + w[i], i + 1)) return true;
        st[i] = false;
        if (!cur || cur + w[i] == length) return false;//开头和结尾
        int j = i;
        while (j < n && w[j] == w[i]) j ++ ;//跳过重复的
        i = j - 1;
    }
    return false;
}
int main()
{
    while (cin >> n, n)
    {
        memset(st, 0, sizeof st);
        sum = 0;
        for (int i = 0; i < n; i ++ )
        {
            cin >> w[i];
            sum += w[i];
        }
        sort(w, w + n);
        reverse(w, w + n);//顺序优化
        length = 1;
        while (true)
        {
            if (sum % length == 0 && dfs(0, 0, 0))
            {
                cout << length << endl;
                break;
            }
            length ++ ;
        }
    }
}

4.https://www.acwing.com/problem/content/170/

枚举每一层DFS即可,下面考虑剪枝:

我们记最上层为1,可以得到:

S={R_{m}^{2}}+\sum_{i=1}^{m}2*R_{i}^{}*H_{i}^{}

N=\sum_{i=1}^{m}R_i{}^{2}*H_{i}

1.我们自底向上搜,同时先枚举R(因为平方)(从大到小)

2.我们再考虑可行性剪枝:

由于N-V\geqslant R_{u}^{2}*h_{u}

我们可以得到枚举的范围:

u\leqslant R_{u}\leqslant min(N-V,R_{u+1}-1)

u\leqslant H_{u}\leqslant min(H_{u+1}-1,N-V/R_{u}^{2})

同时我们可以估计前几层的最小S/V:

于是需要满足:

V+minV(u)\leqslant n     S+minS(u)\leqslant ans

最后我们考虑对公式的放缩:

S_{1\rightarrow u}=2/R_{u+1}*\sum_{k=1}^{u}R_{k}*H_{k}*R_{u+1}> 2/R_{u+1}*(N-V)

于是我们把这个估计的加上现在的S判断与ans的大小关系即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 25, INF = 1e9;
int n, m;
int minv[N], mins[N];
int R[N], H[N];
int ans = INF;
void dfs(int u, int v, int s)
{
    if (v + minv[u] > n) return;
    if (s + mins[u] >= ans) return;
    if (s + 2 * (n - v) / R[u + 1] >= ans) return;
    if (!u)
    {
        if (v == n) ans = s;
        return;
    }
    for (int r = min(R[u + 1] - 1, (int)sqrt(n - v)); r >= u; r -- )
        for (int h = min(H[u + 1] - 1, (n - v) / r / r); h >= u; h -- )
        {
            int t = 0;
            if (u == m) t = r * r;
            R[u] = r, H[u] = h;
            dfs(u - 1, v + r * r * h, s + 2 * r * h + t);
        }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i ++ )
    {
        minv[i] = minv[i - 1] + i * i * i;
        mins[i] = mins[i - 1] + 2 * i * i;
    }
    R[m + 1] = H[m + 1] = INF;
    dfs(m, 0, 0);
    if (ans == INF) ans = 0;
    cout << ans << endl;
}

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

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

相关文章

秋招突击——算法练习——8/3——马上消费笔试总结——{距离为一的字符串、组合数遍历}

文章目录 引言正文第一题&#xff1a;距离为1的字符串个人实现修正实现 第二题&#xff1a;三角形数个人实现反思实现比较对象使用equalsCollections.sort方法 总结 引言 今天的笔试难度不算大&#xff0c;但是自己的做的很糟糕&#xff0c;发现了很多问题&#xff0c;很多模板…

目标检测,目标跟踪,目标追踪

个人专做目标检测&#xff0c;目标跟踪&#xff0c;目标追踪&#xff0c;deepsort。YOLOv5 yolov8 yolov7 yolov3运行指导、环境配置、数据集配置等&#xff08;也可解决代码bug&#xff09;&#xff0c;cpu&#xff0c;gpu&#xff0c;可直接运行&#xff0c;本地安装或者远程…

JVM-类加载器和双亲委派机制

什么是类加载器&#xff1f; 类加载器是Jvm的重要组成之一&#xff08;类加载器、运行时数据区、执行引擎、本地库接口、本地方法库&#xff09;&#xff0c;负责读取java字节码并将其加载到Jvm中的组件 类加载器的分类 Java中的类加载器可以分为以下几种&#xff1a; 1. 启…

Yolov8在RK3588上进行自定义目标检测(一)

1.数据集和训练模型 项目地址&#xff1a;https://github.com/airockchip/ultralytics_yolov8.git 从github(htps:l/github.com/airockchip/ultralytics_yolov8)上获取yolov8模型。 下载项目&#xff1a; git clone https://github.com/airockchip/ultralytics_yolov8.git …

进程的虚拟内存地址(C++程序的内存分区)

严谨的说法&#xff1a; 一个C、C程序实际就是一个进程&#xff0c;那么C的内存分区&#xff0c;实际上就是一个进程的内存分区&#xff0c;这样的话就可以分为两个大模块&#xff0c;从上往下&#xff0c;也就是0地址一直往下&#xff0c;假如是x86的32位Linux系统&#xff0c…

InstantID节点安装遇到的问题与解决办法

原来在一台没有显卡支持的电脑上安装InstantID节点使用没有问题&#xff0c;将安装好的ComfyUI&#xff08;简称ComfyUI_CPU_OK包&#xff09;复制到一台有显卡支持的电脑上&#xff0c;竟然发现InstantID节点异常不能使用&#xff08;按道理应该能正常运行才对&#xff09;&am…

吴恩达机器学习L1W3L06-逻辑回归的梯度下降

目标 在本实验室&#xff0c;你可以看到 更新逻辑回归的梯度下降。在一个熟悉的数据集上探索梯度下降 import copy, math import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_common import dlc, plot_data, plt_tumor_data, sigmoid,…

SQL注入实例(sqli-labs/less-3)

0、初始页面 1、确定闭合字符 确定为字符型注入 ?id1 and 11 ?id1 and 12 确定闭合字符为 ‘) ?id1 ?id1) 2、确定表的列数 确定查询表的列数为3 ?id1) order by 3 -- 3、确定回显位置 确定回显位置为第二列和第三列 ?id-1) union select 1,2,3 -- 4、爆库名 …

MySQL数据库——数据库基础

二、数据库基础 1.主流数据库 SQL Sever:微软的产品&#xff0c;.Net程序员的最爱&#xff0c;中大型项目。Oracle:甲骨文产品&#xff0c;适合大型项目&#xff0c;复杂的业务逻辑&#xff0c;并发一般来说不如MySQL。MySQL&#xff1a;世界上最受欢迎的数据库&#xff0c;属…

《Advanced RAG》-01-朴素RAG存在的问题

摘要 文章阐述了RAG技术如何通过整合外部知识源来提升大型语言模型&#xff08;LLM&#xff09;的性能&#xff0c;使其能够产生更精确、上下文感知的回应&#xff0c;并减少幻觉现象。 自2023年以来&#xff0c;RAG已成为基于LLM的系统中最流行的架构&#xff0c;许多产品依赖…

一文彻底搞懂Fine-tuning - 预训练和微调(Pre-training vs Fine-tuning)

最近这一两周看到不少互联网公司都已经开始秋招提前批了。不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解…

推荐算法学习记录2.2——kaggle数据集的动漫电影数据集推荐算法实践——基于内容的推荐算法、协同过滤推荐

1、基于内容的推荐&#xff1a; 这种方法根据项的相关信息&#xff08;如描述信息、标签等&#xff09;和用户对项的操作行为&#xff08;如评论、收藏、点赞等&#xff09;来构建推荐算法模型。它可以直接利用物品的内容特征进行推荐&#xff0c;适用于内容较为丰富的场景。‌…

VBA学习(22):动态显示日历

这是在ozgrid.com论坛上看到的一个贴子&#xff0c;很有意思&#xff0c;本来使用公式是可以很方便在工作表中实现日历显示的&#xff0c;但提问者因其需要&#xff0c;想使用VBA实现动态显示日历&#xff0c;即根据输入的年份和月份在工作表中显示日历。 下面是实现该效果的VB…

web、nginx

一、web基本概念和常识 ■ Web:为用户提供的一种在互联网上浏览信息的服务,Web服务是动态的、可交互的、跨平台的和图形化的。 ■ Web 服务为用户提供各种互联网服务,这些服务包括信息浏览服务,以及各种交互式服务,包括聊天、购物、学习等等内容。 ■ Web 应用开发也经过了几…

C#中计算矩阵(数学库下载和安装)

1、一步步建立一个C#项目 一步步建立一个C#项目(连续读取S7-1200PLC数据)_s7协议批量读取-CSDN博客文章浏览阅读1.7k次&#xff0c;点赞2次&#xff0c;收藏4次。这篇博客作为C#的基础系列&#xff0c;和大家分享如何一步步建立一个C#项目完成对S7-1200PLC数据的连续读取。首先…

如何解决C#字典的线程安全问题

前言 我们在上位机软件开发过程中经常需要使用字典这个数据结构&#xff0c;并且经常会在多线程环境中使用字典&#xff0c;如果使用常规的Dictionary就会出现各种异常&#xff0c;本文就是详细介绍如何在多线程环境中使用字典来解决线程安全问题。 1、非线程安全举例 Dictio…

文件搜索 36

删除文件 文件搜索 package File;import java.io.File;public class file3 {public static void main(String[] args) {search(new File("D :/"), "qq");}/*** 去目录搜索文件* param dir 目录* param filename 要搜索的文件名称*/public static void sear…

探索Prefect:Python自动化的终极武器

文章目录 探索Prefect&#xff1a;Python自动化的终极武器背景&#xff1a;自动化的呼唤Prefect&#xff1a;自动化的瑞士军刀安装Prefect&#xff1a;一键启动基础用法&#xff1a;Prefect的五招场景应用&#xff1a;Prefect的实战演练常见问题&#xff1a;Prefect的故障排除总…

字节一面面经

1.redis了解吗&#xff0c;是解决什么问题的&#xff0c;redis的应用&#xff1f; Redis 是一种基于内存的数据库&#xff0c;常用的数据结构有string、hash、list、set、zset这五种&#xff0c;对数据的读写操作都是在内存中完成。因此读写速度非常快&#xff0c;常用于缓存&…

IDEA的疑难杂症

注意idea版本是否与maven版本兼容 2019idea与maven3.6以上不兼容 IDEA无法启动 打开idea下载安装的目录&#xff1a;如&#xff1a;Idea\IntelliJ IDEA 2024.1\bin 在bin下面找到 打开在最后一行添加暂停 pause 之后双击运行idea.bat 提示找不到一个jar包&#xff0c;…