2022牛客蔚来杯第三场A C J

本文探讨了两个计算机科学问题:字符串拼接的字典序最小化和十字路口最短路径。对于字符串问题,利用字符哈希和比较函数实现最优排序;在最短路径问题中,将十字路口抽象为节点,转向视为边权,通过Dijkstra算法求解最少红灯数。这两个问题展示了数据结构和算法在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

2022牛客蔚来杯第三场

C.Concatenation

  • 题意

​ 给n个字符串,最后拼接成一个字典序最小的大串

  • 题解

    • 正解是Trie树,不会。
    • 题目其实可以转换成,哪个串放在前面是最优的,即存在可以比较出来的最优贡献顺序

    假设a串放在前面更优

    则有a+b<b+a (相加得到的是两个串拼凑之后的值)

    a✖️261+b < b✖️262+a (字符哈希思路,[a]代表a串的长度)

    化简得 a/(263-1) < b/(264-1)

    即每个串都可以通过自身的价值来判断是否更优,所以可以以此为排序式子排出最优的顺序,最后直接输出即可

  • 代码

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

using namespace std;
const int N=2e6+10;

string s[N];
bool cmp(string &s1,string &s2) {
    return s1+s2<s2+s1;
}

int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>s[i];
    sort(s,s+n,cmp);
    for(int i=0;i<n;i++) cout<<s[i];
    
    return 0;
}

J.Journey

  • 题意

    • 给定n个十字路口,以及每个路口逆时针四个方向对着的路口是哪个
    • 在路口只有右转不需要等红灯,转向其他方向都需要等红灯
    • 给定起始边和终点边,问最少经历多少个红灯
  • 题解

    • 抽象题目,可以发现是一个最短路问题

    • 建图,把每条路(cross_a,cross_b)视作点,而把每个十字路口看作边,等红灯看做边权为1,不等红灯看做边权为0

    • 如何确定边权是0还是1,即如何确定从某点(某条路)到下一个点(下一条路)是否为向右转。

      以0,1,2,3作为四个方向(逆时针数值增大),当一条路(u,v)即u->v,想知道下一个点(下一条路)是不是右转,即到点(v,m)是否右转,我们只需要比对中心v指向u的方向和v指向m的方向,是不是可以逆时针可以u到达m。即v路口指向u的方向数值加一是不是v指向m方向。

    • 正权最短路,直接dijkstra就行

  • 代码

#include <iostream>
#include <queue>
#include <map>

using namespace std;
const int N=5e5+10;

int n,s1,s2,t1,t2;
int cross[N][4];
map<int,bool> st[N];
struct Node{
    int u,v,w;
    bool operator<(const Node &t) const{//优先队列排序和重载是反的,从小到大排序后优先选择边权小的走
        return w>t.w;
    }
};

int get_dir(int u,int v){//得到u->v这条路右转的方向是什么
    for(int i=0;i<4;i++)
        if(cross[v][i]==u)//找到v->u的方向再逆时针转动90度,即v->u方向数值+1
            return (i+1)%4;
    return -1;
}

int dijkstra() {
    priority_queue<Node> q;
    q.push({s1,s2,0});//起点
    
    while(q.size()) {
        auto [u,v,w]=q.top();
        q.pop();
        
        if(st[u][v]) continue;//如果走过就下一个点
        st[u][v]=1;//走过标记
        
        if(u==t1&&v==t2) return w;//到达终点输出距离
        
        int dir=get_dir(u,v);//得到下一个右转的方向数值
        for(int i=0;i<4;i++) {//扩展路线
            if(st[v][cross[v][i]]) continue;//如果下一个点已经走过,舍弃
            if(dir==i) q.push({v,cross[v][i],w});//右转,边权+0
            else q.push({v,cross[v][i],w+1});//非右转,边权+1
        }
    }
    return -1;//走不到终点
}

int main() {
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=0;j<4;j++)
            cin>>cross[i][j];//第i个路口的j方向是哪个路口
    cin>>s1>>s2>>t1>>t2;
    cout<<dijkstra()<<'\n';
    
    return 0;
}

A.Ancestor

  • 题意

  • 题解

    • lca板子题
  • 代码



  1. b ↩︎

  2. a ↩︎

  3. a ↩︎

  4. b ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值