搜索训练(dfs+bfs)持续更新

DFS

[NOIP2000 提高组] 单词接龙

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beastastonish,如果接成一条龙则变为 beastonish,另外相邻的两部分不能存在包含关系,例如 atatide 间不能相连。

输入格式

输入的第一行为一个单独的整数 \(n\) 表示单词数,以下 \(n\) 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。

输出格式

只需输出以此字母开头的最长的“龙”的长度。

样例 #1

样例输入 #1

5
at
touch
cheat
choose
tact
a

样例输出 #1

23

提示

样例解释:连成的“龙”为 atoucheatactactouchoose

\(n \le 20\)

题解:

首先预处理出来上一个词为第i个词,当前词为第j个词的时候,后缀与前缀相同的时候为多少记为给g[i][j]。然后模拟插入过程即可。

AC代码

#include <bits/stdc++.h>
#define Howardlhhhr ios::sync_with_stdio(false);cout.tie(0);cin.tie(0);
using namespace std;
const int N = 22;
string word[N];
int g[N][N],used[N];
int n,ans;
void dfs(string dragon,int last)
{
    ans = max(ans,(int)dragon.size());
    used[last] ++;

    for(int i = 0;i<n;i++)
    {
        if(g[last][i]&&used[i]<2)
        {
            dfs(dragon + word[i].substr(g[last][i]),i);
        }
    }

    used[last] --;
}
int main()
{
    Howardlhhhr
    cin >> n;
    for(int i = 0;i<n;i++) cin >> word[i];
    for(int i = 0;i<n;i++)
    {
        for(int j = 0;j<n;j++)
        {
            string a = word[i],b = word[j];
            for(int k = 1;k<min(a.size(),b.size());k++)
            {
                if(a.substr(a.size()-k,k) == b.substr(0,k))
                {
                    g[i][j] = k;
                    break;
                }
            }
        }
    }
    char start;
    cin >> start;
    for(int i = 0;i<n;i++)
    {
        if(word[i][0] == start)
        {
            dfs(word[i],i);
        }
    }
    cout << ans << endl;
    return 0;
}

[USACO05DEC] Scales S

题目描述

约翰有一架用来称牛的体重的天平。与之配套的是 $ N \ ( 1 \leq N \leq 1000 ) $ 个已知质量的砝码(所有砝码质量的数值都在 \(32\) 位带符号整数范围内)。

每次称牛时,他都把某头奶牛安置在天平的某一边,然后往天平另一边加砝码,直到天平平衡,于是此时砝码的总质量就是牛的质量(约翰不能把砝码放到奶牛的那边,因为奶牛不喜欢称体重,每当约翰把砝码放到她的蹄子底下,她就会尝试把砝码踢到约翰脸上)。

天平能承受的物体的质量不是无限的,当天平某一边物体的质量大于 $ C \ ( 1 \leq C \leq 2^{30} ) $ 时,天平就会被损坏。砝码按照它们质量的大小被排成一行。并且,这一行中从第 \(3\) 个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。

约翰想知道,用他所拥有的这些砝码以及这架天平,能称出的质量最大是多少。由于天平的最大承重能力为 \(C\),他不能把所有砝码都放到天平上。

现在约翰告诉你每个砝码的质量,以及天平能承受的最大质量,你的任务是选出一些砝码,使它们的质量和在不压坏天平的前提下是所有组合中最大的。

输入格式

\(1\) 行输入两个用空格隔开的正整数 $ N $ 和 $ C $。

\(2\) 到 $ N+1 $ 行:每一行仅包含一个正整数,即某个砝码的质量。保证这些砝码的质量是一个不下降序列。

输出格式

输出一个正整数,表示用所给的砝码能称出的不压坏天平的最大质量。

样例 #1

样例输入 #1

3 15
1
10
20

样例输出 #1

11

题解:

可行性剪枝:如果当前选的砝码已经大于最大可选的量的话,那么这条路无论怎么选,都是一个不合法的方案,故剪枝。
搜索顺序:从大到小依次搜索,因为这样能够让决策可选择性越来越少,可以先搜出答案以排除后面的答案

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
typedef long long LL;
LL a[N],sum[N];
LL n,c;
LL ans;
void dfs(int k,LL now)
{
    if(now > c) return;
    if(now + sum[k-1]<=c)
    {
        ans = max(ans,now+sum[k-1]);
        return;
    }
    ans = max(ans,now);
    for(int i = k-1;i;i--)
    {
        if(a[i] < c )dfs(i,now+a[i]);
    }
}
int main()
{
    scanf("%lld%lld",&n,&c);
    for(int i = 1;i<=n;i++) scanf("%lld",&a[i]),sum[i] = sum[i-1] + a[i];
    dfs(n+1,0);
    printf("%lld\n",ans);
    return 0;
}

[NOI1999] 生日蛋糕

题目描述

7 月 17 日是 Mr.W 的生日,ACM-THU 为此要制作一个体积为 \(N\pi\)\(M\) 层生日蛋糕,每层都是一个圆柱体。

设从下往上数第 \(i\)\(1 \leq i \leq M\))层蛋糕是半径为 \(R_i\),高度为 \(H_i\) 的圆柱。当 \(i \lt M\) 时,要求 \(R_i \gt R_{i+1}\)\(H_i \gt H_{i+1}\)

由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积 \(Q\) 最小。

请编程对给出的 \(N\)\(M\),找出蛋糕的制作方案(适当的 \(R_i\)\(H_i\) 的值),使 \(S=\dfrac{Q}{\pi}\) 最小。

(除 \(Q\) 外,以上所有数据皆为正整数)

输入格式

第一行为一个整数 \(N\)\(N \leq 2 \times 10^4\)),表示待制作的蛋糕的体积为 \(N\pi\)

第二行为 \(M\)\(M \leq 15\)),表示蛋糕的层数为 \(M\)

输出格式

输出一个整数 \(S\),若无解,输出 \(-1\)

样例 #1

样例输入 #1

100
2

样例输出 #1

68

题解

可行性剪枝:如果当前可以选的最大的体积比当前必须选的最小的体积要小,那么不可行,故剪枝
最优性剪枝:如果当前已经选的体积,加上估计最小值(后文会推导)要大于当前答案,后面怎么选都不可能是最优,故剪枝
搜索顺序:从大到小放体积
估计最小值推导
假设上面一层是1,最下面一层是是m

\[\sum_{k=1}^u S_k = \sum_{k=1}^u 2\pi r_kh_k = \frac{\sum_{k=1}^u \pi r_kh_kr_{u+1}}{2r_{u+1}} \leq \frac{\sum_{k=1}^u \pi r_k^2h_k}{2r_{u+1}} =\frac{\sum_{k=1}^u V_k}{2r_{u+1}} \]

\[\sum_{k=1}^u S_k \leq \frac{\sum_{k=1}^u V_k}{2r_{u+1}} \]

故有 此时的面积加上预测面积如果大于当前答案则return
对r和h的限制
首先每一层的r和h的最小值应该等于这一层的层数,(第一层最少且最少是一,故第二层最少是2依次类推),而r取最大,h和剩余体积取最小,h取最大同理。故可以得到下面不等式

\[u \leq r_u \leq min(r_{u+1},\frac{\sqrt{n-V- \sum_{k=1}^{u-1} minV_i}}{u} ) \]

\[u \leq h_u \leq min(h_{u+1},\frac{n-V- \sum_{k=1}^{u-1} minV_i}{u^2} ) \]

AC代码

#include <bits/stdc++.h>
using namespace std;
const int M = 30,INF = 0x3f3f3f3f;
int minv[M],mins[M];
int R[M],H[M];
int n,m;
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()
{
    scanf("%d%d",&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);
    printf("%d\n",ans==INF?-1:ans);
    return 0;
}

BFS

posted @   Howardlhhhr  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示