当前位置: 首页 > news >正文

关于离散化算法的看法与感悟

        在之前,我一直不理解什么是离散化?什么情况下要进行离散化操作?但今天在洛谷上做了一道关于离散化的题目:P1955 [NOI2015] 程序自动分析 - 洛谷,我用寻常的ac不了,于是我就开始看题解以及向deepseek提问,终于理解了什么是离散化操作。下面将基于洛谷上的一篇题解:题解 P1955 【[NOI2015]程序自动分析】 - 洛谷专栏,以及deepseek来介绍一下什么是离散化算法;

        

离散化操作在算法中的解释

离散化(Discretization)是算法中一种常见的数据预处理技术,主要用于将连续数据转换为离散数据或将大范围数据映射到小范围区间。

什么是离散化

离散化本质上是一种数据压缩技术,它:

  1. 将无限或大范围的连续数据映射到有限的小范围离散值

  2. 保持原始数据的相对顺序关系

  3. 减少数据的复杂度同时保留关键信息

离散化的常见场景

  1. 处理大范围数据:当数据范围很大但实际不同值不多时(如1e9范围但只有1e5个不同数)

  2. 降低算法复杂度:某些算法(如树状数组、线段树)需要数据范围较小

  3. 将连续数据分类:如将年龄分段为"儿童"、"青年"、"中年"、"老年"

离散化的基本步骤(离散化三部曲)

  1. 收集所有需要离散化的值

  2. 排序(通常需要去重)

  3. 建立映射关系(通常映射到从0或1开始的连续整数

      离散化操作一般搭配着unique函数(去重),以及lower_bound函数使用,在下面的代码中,我会解释一下我所理解的用完这两个函数之后会达到一个怎样的效果。

        就拿P1955 [NOI2015] 程序自动分析 - 洛谷 该题举例为什么要用离散化操作,以及如何进行离散化操作。

题目描述

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本:假设 x1​,x2​,x3​,⋯ 代表程序中出现的变量,给定 n 个形如 xi​=xj​ 或 xi​=xj​ 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:x1​=x2​,x2​=x3​,x3​=x4​,x4​=x1​,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。

现在给出一些约束满足问题,请分别对它们进行判定。

输入格式

输入的第一行包含一个正整数 t,表示需要判定的问题个数。注意这些问题之间是相互独立的。

对于每个问题,包含若干行:

第一行包含一个正整数 n,表示该问题中需要被满足的约束条件个数。接下来 n 行,每行包括三个整数 i,j,e,描述一个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e=1,则该约束条件为 xi​=xj​。若e=0,则该约束条件为 xi​=xj​。

输出格式

输出包括 t 行。

输出文件的第 k 行输出一个字符串 YES 或者 NO(字母全部大写),YES 表示输入中的第 k 个问题判定为可以被满足,NO 表示不可被满足。

        首先给出我第一次写的只有60分代码:

 

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;struct node{int i,j;
};int flag = 0;
vector<int> vis(1000000);
void dfs(unordered_map<int,vector<int>>& ops,int s,int e){vis[s] = 1;int len = ops[s].size();for (int i = 0;i < len;++i){if (!vis[ops[s][i]]){if (ops[s][i] == e)flag = 1;dfs(ops,ops[s][i],e);}}
}
int main()
{int t;cin>>t;for (int i = 0;i < t;++i){int n;cin>>n;flag = 0;unordered_map<int,vector<int>> ops;vector<node> arr;vis.assign(vis.size(),0);for (int j = 0;j < n;++j){int a,b,c;cin>>a>>b>>c;if (c){ops[a].push_back(b);ops[b].push_back(a);}else{arr.push_back({a,b});}}int len = arr.size();for (int j = 0;j < len;++j){dfs(ops,arr[j].i,arr[j].j);}if (flag){cout<<"NO"<<endl;}else{cout<<"YES"<<endl;}}return 0;
}

        在该代码里我用的是dfs深度搜索来代替并查集去判断两个数是否在同一连通分量中,将输入的数据一一映射到vis数组中,来记录每一个数据是否被访问过。

        但是为什么只有60分呢?可以看一下题目给出的输入的数据的范围:

 

        由图可见数据范围上限是10^9,但是我的vis数组最多也不可能开那么大,去一一映射他输入的数据,因此并不能通过全部测试案例。所以这时候就需要通过用离散化操作来将输入的数据一一映射到一个数组能容纳的大小范围里。

修改过后的代码如下:

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;struct node{int i,j,e;
}arr[100010];
bool cmp(node a,node b){return a.e > b.e;
}int f[200000],book[300000];//初始化并查集
void Init(int len){for (int i = 0;i < len;++i){f[i] = i;}
}
//"查"操作
int find(int x){if (f[x] == x)return x;return f[x] = find(f[x]);//压缩路径
}
//"并"操作
void Union(int x,int y){f[find(x)] = find(y);
}
int main()
{int t;cin>>t;for (int i = 0;i < t;++i){int n;cin>>n;memset(f,0,sizeof(f));memset(book,0,sizeof(book));memset(arr,0,sizeof(arr));int count = 0;for (int i = 0;i < n;++i){//录入原数据cin>>arr[i].i>>arr[i].j>>arr[i].e;book[count++] = arr[i].i;book[count++] = arr[i].j;}//将book数组排序sort(book,book + count);//用unique去重(unique返回的是去重后的数列的尾指针)//len为对book数组去重后的数据量int len = unique(book,book + count) - book;//将book里的原数据一一映射为编号从0到len的形式for (int i = 0;i < n;++i){//寻找原数据进行离散化后的对应编号arr[i].i = lower_bound(book,book + len,arr[i].i) - book;arr[i].j = lower_bound(book,book + len,arr[i].j) - book;}//结束离散化,接下来是正常操作int flag = 0;Init(len);//初始化并查集sort(arr,arr + n,cmp);for (int i = 0;i < n;++i){int x = find(arr[i].i);int y = find(arr[i].j);if (arr[i].e){Union(x,y);}else{if (x == y){flag = 1;break;}}}if (flag){cout<<"NO"<<endl;}else{cout<<"YES"<<endl;}}return 0;
}

        如果看不太懂的话可以移步题解 P1955 【[NOI2015]程序自动分析】 - 洛谷专栏。该篇只是记录一下我基于该题对于离散化操作的看法及感悟。

http://www.xdnf.cn/news/275743.html

相关文章:

  • 软考-软件设计师中级备考 8、进程管理
  • 49认知干货:产品的生命周期及类型汇总
  • 【Java项目脚手架系列】第一篇:Maven基础项目脚手架
  • Rust的安全卫生原则
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】2.2 多表关联技术(INNER JOIN/LEFT JOIN/FULL JOIN)
  • C++八股--6--mysql 日志与并发控制
  • WSL在D盘安装Ubuntu
  • 纯文本Text转Html网页转换器
  • 方案精读:110页华为云数据中心解决方案技术方案【附全文阅读】
  • 项目收尾管理
  • 时序分解 | Matlab基于WOA-MVMD鲸鱼算法优化多元变分模态分解
  • C盘莫名其妙一直变大
  • 智能工厂边缘计算:从数据采集到实时决策
  • WPF之尺寸属性层次
  • 如何从GitHub上调研优秀的开源项目,并魔改应用于工作中?
  • 【言语理解】中心理解题目之选项分析
  • Unity与Unreal Engine(UE)的深度解析及高级用法
  • 【AI面试准备】模型自动化评估经验
  • MCP协议与Dify集成教程
  • 华中科技大学系统结构慕课部分答案
  • 33.降速提高EMC能力
  • 深度学习中的数据增强:提升食物图像分类模型性能的关键策略
  • 【自存】python使用matplotlib正常显示中文、负号
  • Android ART运行时无缝替换Dalvik虚拟机的过程分析
  • Android运行时ART加载OAT文件的过程
  • 跨学科项目式学习的AI脚手架设计:理论框架与实践路径研究
  • 从头训练小模型: 4 lora 微调
  • 【51单片机6位数码管显示时间与秒表】2022-5-8
  • 基于DeepSeek R1知识对Qwen2.5 3B模型进行蒸馏
  • 55、【OS】【Nuttx】编码规范解读(三)