思维题(上) 长期更新

本文是一系列关于算法和思维题目的解析,包括Ehab and Path-etic MEXs、WeirdSort、区间选点等多个题目。文章通过详细阐述题意、思路以及易错点,帮助读者理解解题策略,提升算法能力。例如,Ehab and Path-etic MEXs中,通过保证路径标号最大值最小来解决问题;WeirdSort中,利用排序而非并查集实现数组非降序排列。
摘要由CSDN通过智能技术生成

1. Ehab and Path-etic MEXs

题意

给边上打0~n-2这n-1个标签,使得任意两点之间的路径标号的最大值最小。输出边上的标号。

思路

存在度数大于等于3的点,任选一个度数大于三的点,任选其三条边标记上0,1,2,然后其他所有边随便标。

解释:

  1. 首先各点对的mex的最大值的最小值不能为0,因为至少有边权为0。
  2. 接着也不能为1,因为树是联通的,必然有一条路径包含0,1(任意选两个边,也会被某一条路径包含)。
  3. 所以我们尝试能不能让所求的值为2,发现只要0,1,2连接在同一个节点上,不可能有路径会同时经过0,1,2。
    在这里插入图片描述
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int maxn = 1e5+10;
int ans[maxn];
int n;
int vis[maxn];
PII a[maxn];

int main(){
   
    cin>>n;
    int from,to,pos = 0;
    for(int i=1;i<n;i++){
   
        cin>>from>>to;
        vis[from] ++, vis[to] ++;
        a[i].first = from, a[i].second = to;
        if(! pos){
   
            if(vis[from] >= 3)
                pos = from;
            if(vis[to] >= 3)
                pos = to;
        }
    }

    if(! pos){
   
        for(int i=0;i<n-1;i++)
            cout<<i<<' ';
        cout<<endl;
    }else{
   
        int p = 0;
        memset(ans, -1, sizeof(ans));
        for(int i=1;i<n;i++){
   
            if(a[i].first != pos && a[i].second != pos)
                continue;
            else{
   
                ans[i] = p ++;
            }
        }
        for(int i=1;i<n;i++){
   
            if(ans[i] != -1)
                continue;
            else
                ans[i] = p ++;
        }
        for(int i=1;i<n;i++){
   
            cout<<ans[i]<<' ';
        }
        cout<<endl;
    }
    return 0;
}

2. WeirdSort

题意

给了两组数,第二组b[i]表示第一组的i和i+1可以交换位置,问可不可以把第一组数换成非降序数组。

思路

把根据b数组给a中的数一段一段排序。看最后是不是非降序。没必要用并查集,我自己没注意写成并查集了而已。

#include<cstring> 
#include<algorithm>
#include<iostream>
#include<cstdio>
const int maxn = 105;
typedef long long ll;
using namespace std;
int f[maxn],a[maxn];

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

int init(){
   
    for(int i=0; i<maxn; i++){
   
        f[i] = i;
    }
}

int main(){
   
    int t; cin>>t;
    while(t --){
   
        int n,m;
        cin>>n>>m;
        init();
        for(int i=1;i<=n;i++){
   
            cin>>a[i];
        }
        int temp;
        for(int i=1;i<=m;i++){
   
            cin>>temp;
            int p1 = find(temp);
            int p2 = find(temp + 1);
            if(p1 != p2){
   
                f[p1] = p2;
            }
        }
        for(int i=1, j=i + 1;i<=n && j <= n;i = j){
   
            for(int p1 = find(i), p2 = find(j); j <= n && p1 == p2; j ++){
   
                p1 = find(i), p2 = find(j);
                if(!(j <= n && p1 == p2))
                    break;
            }
            sort(a+i,a+j);
        }
        int flag = 1;
        for(int i=1;i<n;i++){
   
            if(a[i] > a[i + 1]){
   
                flag = 0;
                break;
            }
        }
        if(flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
	return 0;
}

3. 区间选点

题意

求给定的若干个区间内,每个区间内都有点的最少点数。

思路

贪心。
[假算法]先考虑按照左端点排序,在不能借助上一个点的情况下,在这一个区间的右端点新建一个点。
[真算法]按右端点排序,不能借助上一个点的情况下,在右端点新建一个点。
假算法为什么假呢。如图1,加算法会在粗红线建立一个点,而忽略了左下角的区间。真算法如图2。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411150835272.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzE0NTM5Nw==,size_16,color_FFFFFF,t_70
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值