每日一练c++题目日刊 | 第十一期

本文介绍了C++实现的多个算法题目,包括Kruskal算法求解最小生成树,动态规划解决最长公共子序列问题,以及结合二分法的动态规划解题策略,如最小表示法和最小代价带权图的最大点双问题。同时,还探讨了贪心算法与二分查找在最大子矩形和滑动窗口最大值问题中的应用。
摘要由CSDN通过智能技术生成

Kruskal算法:最小生成树

题目背景故事

你是一名建筑工人,负责在一个城市中建造一座桥。你需要把这座桥连接的两个岸边的点连起来,并且要使得连接的边的权值和最小。

题目描述

给定一张带权的无向图,求出其最小生成树。

输入描述

第一行包含两个整数n和m,分别表示点数和边数。

接下来m行,每行包含三个整数u, v, w,表示一条从点u到点v的有向边,权值为w。

输出描述

输出最小生成树的权值和。

输入样例

4 5
1 2 3
1 3 4
4 2 6
4 3 5
2 3 7

输出样例

14

解题思路

这道题我们可以使用Kruskal算法来解决。Kruskal算法是一种用于求解最小生成树的算法,它的核心思想是将图中所有边按照权值从小到大排序,然后依次加入边,如果加入后不会形成环,就加入这条为了判断一条边是否会形成环,我们可以使用并查集来维护连通性。每次加入一条边时,我们先将两个端点所在的集合合并,然后判断两个端点是否在同一个集合中,如果不是,就加入这条边。

C++代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1010;

struct Edge
{
   
    int u, v, w;
} edges[N];

int p[N];

int find(int x)
{
   
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
   
    int n, m;
    cin >> n >> m;

    for (int i = 0; i < m; i ++ )
        cin >> edges[i].u >> edges[i].v >> edges[i].w;

    for (int i = 1; i <= n; i ++ ) p[i] = i;

    sort(edges, edges + m, [](Edge a, Edge b){
    return a.w < b.w; });

    int res = 0;
    for (int i = 0; i < m; i ++ )
    {
   
        int u = edges[i].u, v = edges[i].v;
        int t1 = find(u), t2 = find(v);
        if (t1 != t2)
        {
   
            p[t1] = t2;
            res += edges[i].w;
        }
    }

    cout << res << endl;

    return 0;
}

动态规划:最长公共子序列

题目背景故事

你是一名研究生,正在研究两个DNA序列的相似性。你需要找出这两个DNA序列的最长公共子序列,并确定它们的相似度。

题目描述

给定两个字符串A和B,求出它们的最长公共子序列的长度。

输入描述

第一行包含两个字符串A和B。

输出描述

输出最长公共子序列的长度。

输入样例

abcde
abcdf

输出样例

4

解题思路

这道题我们可以使用动态规划来解决。我们可以定义一个二维数组dp[i][j]表示字符串A的前i个字符和字符串B的前j个字符的最长公共子序列的长度。

对于每一个dp[i][j],我们可以由dp[i-1][j]和dp[i][j-1]转移而来,但是如果A[i]==B[j],我们就可以加上dp[i-1][j-1]的值。

状态转移方程如下:

d p [ i ] [ j ] = max ⁡ ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j]=\max(dp[i-1][j],dp[i][j-1]) dp[i][j]=max(dp[i1][j],dp[i][j1])

d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 ( A [ i ] = = B [ j ] ) dp[i][j]=dp[i-1][j-1]+1(A[i]==B[j]) dp[i][j]=dp[i1][j1]+1(A[i]==B[j])

C++代码

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1010;

char A[N], B[N];

int dp[N][N];

int main()
{
   
    cin >> A + 1 >> B + 1;

    int n = strlen(A + 1), m = strlen(B + 1);

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
   
            dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            if (A[i] == B[j]) dp[i][j] = dp[i-1][j-1] + 1;
        }

    cout << dp[n][m] << endl;

    return 0;
}

动态规划+二分:最小表示法

题目背景故事

你是一名研究生,正在研究两个DNA序列的相似性。你需要找出这两个DNA序列的最长公共子序列,并确定它们的相似度。

题目描述

给定两个字符串A和B,求出它们的最长公共子序列的长度。

输入描述

第一行包含两个字符串A和B。

输出描述

输出最长公共子序列的长度。

输入样例

abcde
abcdf

输出样例

4

解题思路

这道题我们可以使用动态规划来解决。我们可以定义一个二维数组dp[i][j]表示字符串A的

评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小刘较瘦

打赏即动力,打赏即鼓励。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值