imos-累积和法
在解AOJ 0531 Paint Color时,学到了一个累积和的妙用——imos法,由于原文是日语,所以特意翻译过来。值得一提的是,作者Kentaro Imajo跟鄙人同龄,却已取得如此多的成就,而鄙人一无所成,实在汗颜。
imos法
imos法是将累积和算法拓展到多次元、高次空间的方法。虽然程序竞赛中出题最多不过2次元1次,但是2012年Kentaro Imajo将其用于高次元高次空间,在信号处理/图像处理领域取得了成就。
基础imos法
最简单的imos法是1次元0次系数的求解思想。如图,有三个俄罗斯方块在一起,悬空的部分会掉下去,求从左到右的高度?这个高度就是横坐标固定时,上面矩形高度之和。这就是最简单的imos法。
例题
你在经营一个咖啡厅,你的咖啡厅里每个客人在S_i时刻进店,E_i时刻出店。求店里最多有多少客人?(客人最多C个,时刻在T内。如果有多人同时进店出店,先算出店的人)。
朴素的解法
朴素的思想是,计算每个时刻客户的数量,从中找出最大值。但是,复杂度是\(O(CT)\)
#include <iostream>
#include <algorithm>
using namespace std;
#define C 4
#define T 10
// 每个客人的进入时间
int S[C] = { 1, 3, 5, 7 };
// 每个客人的离开时间
int E[C] = { 2, 8, 6, 8 };
// 店里的人数
int table[T];
int main(int argc, char *argv[])
{
memset(table, 0, sizeof(table));
for (int i = 0; i < C; i++)
{
// 从时间 S[i] 到 E[i] - 1 店里人数计数加一
for (int j = S[i]; j < E[i]; j++)
{
table[j]++;
}
}
// 找最大値
cout << *max_element(table, table + T) << endl;
system("pause");
return 0;
}
imos法解法
imos法的基本方向是,只统计出入店时刻的人数变化(我个人理解相当于求导),入店+1,出店-1。最终统计的时候,需要将每个时刻加上前一个时刻的统计量(我个人理解相当于求积分),其中的最大值就是所求。记录复杂度O(C),累加复杂度O(T),所以整体复杂度O(C+T)。
#include <iostream>
#include <algorithm>
using namespace std;
#define C 4
#define T 10
// 每个客人的进入时间
int S[C] = { 1, 3, 5, 7 };
// 每个客人的离开时间
int E[C] = { 2, 8, 6, 8 };
// 店里的人数
int table[T];
int main(int argc, char *argv[])
{
memset(table, 0, sizeof(table));
for (int i = 0; i < C; i++)
{
table[S[i]]++; // 入店+1
table[E[i]]--; // 出店-1
}
// 累加
for (int i = 1; i < T; i++)
{
table[i] += table[i - 1];
}
// 找最大値
cout << *max_element(table, table + T) << endl;
system("pause");
return 0;
}
推广到二次元
\(imos\)相对于朴素方法的一个优点就是随着次元增大复杂度的降低越明显。
例题
你在玩一个抓怪兽的游戏,现在你面前是一张W*H的地图,地图里有N种怪物。怪物i只会在左下角为(B_i,C_i),右上角为(A_i,D_i)的矩形区域内出现。求单位区域内最多有多少种怪兽?
朴素解法
朴素的解法就是计算每一个单位区域内出现的怪兽数,然后找出最大值。复杂度是O(NWH)。
#include <iostream>
#include <algorithm>
using namespace std;
#define W 6
#define H 6
#define N 4
// 左下角坐标
int B[N] = {3,4,3,5,};
int C[N] = {0,1,2,2,};
// 右上角坐标
int A[N] = {0,3,2,2,};
int D[N] = {3,2,3,5,};
// 地图上的分布结果
int tiles[H][W];
int main(int argc, char *argv[])
{
memset(tiles, 0, sizeof(tiles));
for (int i = 0; i < N; i++)
{
// 怪兽 i 出现的范围 [(A[i],C[i]), (B[i],D[i])) 内的计数加一
for (int y = C[i]; y < D[i]; y++)
{
for (int x = A[i]; x < B[i]; x++)
{
tiles[y][x]++;
}
}
}
// 求最大値
cout << *max_element(tiles[0], tiles[0] + H * W) << endl;
system("pause");
return 0;
}
imos法解法
矩形的左上角 (A[i],C[i]) +1 ,右上角 (A[i],D[i]) −1,左下角 (B[i],C[i]) −1 ,右下角(B[i],D[i]) +1 ,统计最终结果之前累加。加一减一 O(N),累加(WH) 整体复杂度 O(N+WH) 。
#include <iostream>
#include <algorithm>
using namespace std;
#define W 6
#define H 6
#define N 4
// 左下角坐标
int B[N] = {3,4,3,5,};
int C[N] = {0,1,2,2,};
// 右上角坐标
int A[N] = {0,3,2,2,};
int D[N] = {3,2,3,5,};
// 地图上的分布结果
int tiles[H][W];
int main(int argc, char *argv[])
{
memset(tiles, 0, sizeof(tiles));
// 影响力计算 (图 3)
for (int i = 0; i < N; i++)
{
tiles[C[i]][A[i]]++;
tiles[C[i]][B[i]]--;
tiles[D[i]][A[i]]--;
tiles[D[i]][B[i]]++;
}
// 横向累积和 (图 4, 5)
for (int y = 0; y < H; y++)
{
for (int x = 1; x < W; x++)
{
tiles[y][x] += tiles[y][x - 1];
}
}
// 纵向累积和 (图 6, 7)
for (int y = 1; y < H; y++)
{
for (int x = 0; x < W; x++)
{
tiles[y][x] += tiles[y - 1][x];
}
}
cout << *max_element(tiles[0], tiles[0] + H * W) << endl;
system("pause");
return 0;
}
图三:影响力计算
图四:横向累加
图五:横向累加结果
图六:纵向累加
图七:纵向累加结果
更高级的用法
暂时用不到,记录一个地址,有空再看。
参考资料
http://imoz.jp/algorithms/imos_method.html
imos-累积和法的更多相关文章
- paper 83:前景检测算法_1(codebook和平均背景法)
前景分割中一个非常重要的研究方向就是背景减图法,因为背景减图的方法简单,原理容易被想到,且在智能视频监控领域中,摄像机很多情况下是固定的,且背景也是基本不变或者是缓慢变换的,在这种场合背景减图法的应用 ...
- 图像处理算法2——Otsu最佳阈值分割法http://blog.csdn.net/xiaqunfeng123/article/details/17121195
http://blog.csdn.net/xiaqunfeng123/article/details/17121195Otsu法是1979年由日本大津提出的.该方法在类间方差最大的情况下是最佳的,即统 ...
- AtCoder Beginner Contest 260 G // imos(累积和算法)
题目传送门:G - Scalene Triangle Area (atcoder.jp) 题意: 给定大小为N*N的OX矩阵,若矩阵的(s,t)处为O,其覆盖范围为:满足以下条件的所有位置(i,j) ...
- 左神算法进阶班8_1数组中累加和小于等于aim的最长子数组
[题目] 给定一个数组arr,全是正数:一个整数aim,求累加和小于等于aim的,最长子数组,要求额外空间复杂度O(1),时间复杂度O(N) [题解] 使用窗口: 双指针,当sum <= aim ...
- [LeetCode] Missing Number 丢失的数字
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...
- Excel教程(8) - 财务函数
ACCRINT 用途:返回定期付息有价证券的应计利息. 语法:ACCRINT(issue,first_interest, settlement, rate,par,frequency, basis) ...
- Numpy 多维数组简介
 NumPy是一个功能强大的Python库,主要用于对多维数组执行计算.NumPy这个词来源于两个单词-- Numerical和Python.NumPy提供了大量的库函数和操作,可以帮助程序员轻松地 ...
- 3 数据分析之Numpy模块(2)
数组函数 通用元素级数组函数通用函数(即ufunc)是一种对ndarray中的数据执行元素级的运算.我们可以将其看做是简单的函数(接收一个或多个参数,返回一个或者多个返回值). 常用一元ufunc: ...
- NLP相关问题中文本数据特征表达初探
1. NLP问题简介 0x1:NLP问题都包括哪些内涵 人们对真实世界的感知被成为感知世界,而人们用语言表达出自己的感知视为文本数据.那么反过来,NLP,或者更精确地表达为文本挖掘,则是从文本数据出发 ...
随机推荐
- SQL语句加锁分析
背景 MySQL中SQL加锁的情况十分复杂,不同隔离级别.不同索引类型.索引是否命中的SQL加锁各不相同. 然而在分析死锁过程当中,熟知各种情况的SQL加锁是分析死锁的关键,因此需要将MySQL的各种 ...
- Python 【面试强化宝典】
四大数据类型的常用方法 列表常用方法 #1. append 用于在列表末尾追加新的对象 a = [1,2,3] a.append(4) #the result : [1, 2, 3, 4] #2. c ...
- Serlvet容器与Web应用
对启动顺序的错误认识 之前一直有个观点,应用运行在Servlet容器中,因为从Servlet容器与Web应用的使用方式来看,确实很有这种感觉. 我们每次都是启动Servlet容器,然后再启动我们的应用 ...
- Java IO 流--FileUtils 工具类封装
IO流的操作写多了,会发现都已一样的套路,为了使用方便我们可以模拟commosIo 封装一下自己的FileUtils 工具类: 1.封装文件拷贝: 文件拷贝需要输入输出流对接,通过输入流读取数据,然后 ...
- 破解idea2019版本至2089年(windows系统)
1.首先必须安装idea,然后找到安装目录下的bin目录下面 2.编辑俩个以.exe.vmoptions的文件(俩个文件的最后一行都得这样写) 3.重新打开idea,找到help下面的Register ...
- python学习18类4之静态类
'''''''''类的静态方法.普通方法.类方法 静态方法: 用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用. 普通方法: ...
- MFC之动态调用自己写的类库中的类的成员方法
第一步:创建一个要调用的类库 如果是MFC程序使用,可以创建一个MFC的类库,不过依然可以创建一个win32类库.我所知道的,MFC的类库可以分为常规MFC DLL和MFC扩展DLL关于它们之间的区别 ...
- 中国AI觉醒 阿里王坚:云智能将成为大趋势
2019独角兽企业重金招聘Python工程师标准>>> <麻省理工科技评论>新兴科技峰会EmTech China于北京召开.大会中,其中一项热门的讨论便是:中国和美国的科 ...
- 疯子的算法总结(六) 复杂排序算法 ① 归并排序 merge_sort()
归并排序采取了分治的思想,每次分别排左半边和右半边,不断递归调用自己,直到只有一个元素递归结束,开始回溯,调用merge函数,合并两个有序序列,再合并的时候每次给末尾追上一个最大int这样就不怕最后一 ...
- 将A页面提交的数据id传递到B页面
A页面 在A页面跳转到B页面的时候,在url后面可以拼接参数 例如: window.location.href = './B.html?' + id; 跳转到B页面之后,可以通过url地址获取到从A页 ...