2024.9.11

今日总结
1:楼房
这个题目主要用了离散化和线段树来解决。
首先考虑暴力的思想:首先用一个数组来存储每个点的高度,对所有的高度去一个Max
但是这么做肯定会超时。那么我们可以用一个线段树来维护每一个高度的Max使其做到查找的时间为O(1),只考虑可能存在拐点的位置,对每个拐点离散后对每个位置更新最大高度,最后扫描一遍离散序列,统计拐点数量并记录存在的位置,即可求出答案总体时间复杂度O(nlogn)

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
const int M = N << 1;

int n,cnt;
int c[M],f[M],p[M];
//c数组记录离散后的高度
vector<pair<int,int>> v;//记录拐点的坐标

struct Node
{
    int l,r;
    int h;
}s[N];

bool cmp(const Node &x,const Node &y)
{
    return x.h > y.h;
}

int query(const int &x)//查询最大值操作
{
    if(x == f[x]) return x;
    return f[x] = query(f[x]);
}

int main()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
    {
        cin >> s[i].h >> s[i].l >> s[i].r;
        p[i] = s[i].l,p[i + n] = s[i].r;
    }
    sort(s + 1,s + n + 1,cmp);
    sort(p + 1,p + n * 2 + 1);//离散化
    cnt = unique(p + 1,p + n * 2 + 1) - p - 1;
    for(int i = 1;i <= cnt;i ++)
        f[i] = i;//并查集初始化
    for(int i = 1;i <= n;i ++)
    {
        s[i].l = lower_bound(p + 1,p + cnt + 1,s[i].l) - p;
        s[i].r = lower_bound(p + 1,p + cnt + 1,s[i].r) - p;
        for(int j = query(s[i].r - 1);j >= s[i].l;j = query(j - 1))
            c[j] = s[i].h,f[j] = f[j - 1];//更新答案
    }
    for(int i = 1;i <= cnt;i ++)
    {
        if(c[i] != c[i - 1])
        {
            v.push_back({p[i],c[i - 1]});
            v.push_back({p[i],c[i]});//找到节点
        }
    }
    printf("%d\n",v.size());
    for(auto &i : v) 
        cout << i.first << ' ' << i.second << endl;//输出x,y;
    return 0;
}

2:单词游戏

这个题目是一个树形dp的题目。中间使用Floyed,判断那两个单词可以进行匹配,以防漏算掉最优解

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;
const int M = 20;

int n,ans;
int len[M],c[M][M];
char s[M][5 * M];

struct Node
{
    int num,pos;//num表示最大长度
}f[N * 4];

int main()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%s",s[i]);
        len[i] = strlen(s[i]);
        f[1 << (i - 1)].num = len[i];
        f[1 << (i - 1)].pos = i;
        ans = max(ans,len[i]);//运用贪心的思想先记录下最长的单词长度
    }
    for(int i = 1;i <= n;i ++)//两层循环遍历每一个单词
    for(int j = 1;j <= n;j ++)
    {
        if(s[i][len[i] - 1] == s[j][0])//预处理树形dp
            c[i][j] =1;
    }
    for(int i = 1;i < (1 << n);i ++)//运用FLoyed判断两个单词是否可以进行匹配
        if(f[i].num)
            for(int j = 1;j <= n;j ++)
                if(c[f[i].pos][j])
                    if(!(i & 1 << (j - 1)))//是否可以进行匹配
                        if(len[j] + f[i].num > f[i | (1 << (j - 1))].num)//更新num
                        {
                            f[i | (1 << (j - 1))].num = len[j] + f[i].num;//动态转移方程(通过父节点和子节点的转移)
                            f[i | (1 << (j - 1))].pos = j;
                            ans = max(ans,f[i | (1 << (j - 1))].num);
                        }
    printf("%d\n",ans);
    return 0;
}
其实这道题也可以dfs+剪枝也可以解决,第一开始没想到
posted @ 2024-09-11 21:23  Kevinhwbb  阅读(12)  评论(0编辑  收藏  举报