acwing暑假每日一题2022的week2

4273.链表合并

题目戳我

y总讲解里有说,只要不是面试我们就尽量用数组去模拟链表,这样省时省力。

下面简单分析一下这个问题

(1).他说了5位数,那么可以开一个1e5+10的数组就足够了,这样就解决了地址问题,然后权重就是地址存放的值就可以了,但是我们要存放他的next。

(2)所以还需要开一个数组,我们读取完数据,就处理合并就可以了,注意这里我们默认大小的,所以记得if判断一下,然后我们将两个模拟链表顺序存储一下。

(3)借用pair和vector,pair里面是地址和内容,这里我们就不用存储next了,因为我们可以直接用第二个数据的地址就行了,因为我们这里已经给他串连起来了。

(4)最后就是处理一下合并问题,以及输出即可。我这里用的cout处理宽度和前补0麻烦一些,可以选择使用printf来处理会容易很多。

代码:


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <bits/stdc++.h>
using namespace std;

const int maxn=100010;
typedef pair<int, int> PII;
#define x first
#define y second

int head1,head2,n;
int v[maxn],ne[maxn];

int main()
{
    cin >>head1>>head2>>n;
    while(n--){
        int address,value,next;
        cin >>address>>value>>next;
        v[address] = value;
        ne[address] = next;
    }
    vector<PII> a,b;
    for(int i=head1; i!=-1; i=ne[i]) a.push_back({i,v[i]});
    for(int i=head2; i!=-1; i=ne[i]) b.push_back({i,v[i]});
    if(a.size()<b.size()) swap(a,b);
    
    vector<PII> c;
    for(int i=0,j=b.size()-1; i<a.size(); i+=2,j--){
        c.push_back(a[i]);
        if(i+1< a.size() ) c.push_back(a[i+1]);
        if(j>=0) c.push_back(b[j]);
    }
    
    for(int i=0; i<c.size(); i++){
        cout<<setfill('0')<<setw(5)<<c[i].x<<" "<<c[i].y<<" ";
        if(i+1 <c.size()) cout<<setfill('0')<<setw(5)<<c[i+1].x<<endl;
        else cout<<"-1"<<endl;
    }
    
    return 0;
}

4274.后缀表达式

题目戳我​​​​​​​

(1)题目读完了,我们就知道了,递归进行后续遍历,然后记得每个数据都要加个左右括号就行了。

(2)不过我们遍历的时候注意正负号问题,还有他的儿子的处理问题,如果是有俩儿子,那么要输出左右再递归,如果没有儿子直接递归就行了,如果只有一个儿子那也要先输出再递归

(3)最后就是我们如何找到根节点,根节点的特点就是没有父亲节点,利用这一点来找到根节点,我们对所有的儿子节点进行标记,最后没有标记的就是根节点了。

代码:

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

using namespace std;
const int maxn=30;
int n;
string a[maxn];
int l[maxn],r[maxn];
bool st[maxn];  //判断是否有儿子

void dfs(int dd)
{
    cout<<"(";
    
    if(st[l[dd]] && st[r[dd]]){
        dfs(l[dd]);
        dfs(r[dd]);
        cout<<a[dd];
    }else if(!st[l[dd]] && !st[r[dd]]){
        cout<<a[dd];
    }else{
        cout<<a[dd];
        dfs(r[dd]);
    }
    
    cout<<")";
}
int main()
{
    cin >>n;
    for(int i=1; i<=n; i++){
        cin >>a[i]>>l[i]>>r[i];
        if(l[i]!=-1) st[l[i]] = true;   //是否有左儿子
        if(r[i]!=-1) st[r[i]] = true;   //是否有右儿子
    }
    
    int dd;
    for(int i=1; i<=n; i++){
        if(!st[i]){
           dd = i;  //找到根节点
        }
    }
    dfs(dd);    //开始从根节点进行递归查找
    return 0;
}

4275.Dijkstra序列

题目戳我

题目读起来有一点复杂,总结一下就是读入数据后,有K个序列,我们要判断他们是不是Dijkstra序列,也就是跑K次的Dijkstra算法,然后我们来看一下复杂度,题目给的是1000,2s大概是2e8,Dijkstra的朴素写法复杂度是n²级别的,然后算上K大概刚好1e8,可以尝试一下。

代码:

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

using namespace std;
const int maxn=1010;

int n,m;    //点 和 边
int dist[maxn],g[maxn][maxn];   //距离数组 和 读入数据点的数组
bool st[maxn];  //判断当前点是否遍历过
int dd[maxn];   //测试序列数组

bool dijkstra()
{
    memset(dist, 0x3f3f, sizeof dist);
    memset(st, 0, sizeof st);
    dist[dd[0]] = 0; //起始点
    for(int i=0; i<n; i++){
        int q = dd[i];
        for(int j=1; j<=n; j++){
            if(!st[j] && dist[j]<dist[q]){
                return false;
            }
        }
        st[q] = true;
        for (int j = 1; j <=n; j ++ ){
            // if(dist[j] > dist[q] + g[q][j]){
            //     dist[j] = dist[q] + g[q][j]; 
            // }
            dist[j] = min(dist[j],dist[q]+g[q][j]);
        }
    }
    return true;
}
int main()
{
    cin >>n>>m;
    memset(g, 0x3f3f3f3f, sizeof g);    //初始化边
    while(m--){
        int a,b,c;
        cin >>a>>b>>c;
        g[a][b] = g[b][a] = c;
    }
    
    int k;
    cin >>k;
    while(k--){
        for(int i=0; i<n; i++){
            cin >>dd[i];
        }
        if(dijkstra()) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0; 
}

有问题欢迎留言,和我交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值