在解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-累积和法的更多相关文章

  1. paper 83:前景检测算法_1(codebook和平均背景法)

    前景分割中一个非常重要的研究方向就是背景减图法,因为背景减图的方法简单,原理容易被想到,且在智能视频监控领域中,摄像机很多情况下是固定的,且背景也是基本不变或者是缓慢变换的,在这种场合背景减图法的应用 ...

  2. 图像处理算法2——Otsu最佳阈值分割法http://blog.csdn.net/xiaqunfeng123/article/details/17121195

    http://blog.csdn.net/xiaqunfeng123/article/details/17121195Otsu法是1979年由日本大津提出的.该方法在类间方差最大的情况下是最佳的,即统 ...

  3. AtCoder Beginner Contest 260 G // imos(累积和算法)

    题目传送门:G - Scalene Triangle Area (atcoder.jp) 题意: 给定大小为N*N的OX矩阵,若矩阵的(s,t)处为O,其覆盖范围为:满足以下条件的所有位置(i,j) ...

  4. 左神算法进阶班8_1数组中累加和小于等于aim的最长子数组

    [题目] 给定一个数组arr,全是正数:一个整数aim,求累加和小于等于aim的,最长子数组,要求额外空间复杂度O(1),时间复杂度O(N) [题解] 使用窗口: 双指针,当sum <= aim ...

  5. [LeetCode] Missing Number 丢失的数字

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  6. Excel教程(8) - 财务函数

    ACCRINT 用途:返回定期付息有价证券的应计利息. 语法:ACCRINT(issue,first_interest, settlement, rate,par,frequency, basis) ...

  7. Numpy 多维数组简介

     NumPy是一个功能强大的Python库,主要用于对多维数组执行计算.NumPy这个词来源于两个单词-- Numerical和Python.NumPy提供了大量的库函数和操作,可以帮助程序员轻松地 ...

  8. 3 数据分析之Numpy模块(2)

    数组函数 通用元素级数组函数通用函数(即ufunc)是一种对ndarray中的数据执行元素级的运算.我们可以将其看做是简单的函数(接收一个或多个参数,返回一个或者多个返回值). 常用一元ufunc: ...

  9. NLP相关问题中文本数据特征表达初探

    1. NLP问题简介 0x1:NLP问题都包括哪些内涵 人们对真实世界的感知被成为感知世界,而人们用语言表达出自己的感知视为文本数据.那么反过来,NLP,或者更精确地表达为文本挖掘,则是从文本数据出发 ...

随机推荐

  1. vue中data必须是一个函数

    前端面试时经常被问到:“组建中data为什么是函数”? 答案就是:在组件中data必须是一个函数,这样的话,每个实例可以维护一份被返回对象的独立拷贝.

  2. CKEditor与定制

    一 开始使用 官网 基本示例: 搭建服务器(这里使用apache) 下载standard的ckeditor解压放在apache的htdocs的目录下 在htdoc下面新建index.html,写入代码 ...

  3. 下载mp4文件

    实现mp4文件的下载,而不是在线播放 <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  4. python 基础篇 自定义函数

    多态 我们可以看到,Python 不用考虑输入的数据类型,而是将其交给具体的代码去判断执行,同样的一个函数(比如这边的相加函数 my_sum()),可以同时应用在整型.列表.字符串等等的操作中. 在编 ...

  5. pytorch Model Linear实现线性回归CUDA版本

    实验代码 import torch import torch.nn as nn #y = wx + b class MyModel(nn.Module): def __init__(self): su ...

  6. 进阶 Linux基本命令-1

    vmware三种网络模式1,桥接虚拟机直接连接外网,局域网.宿主机电脑不提供路由. 2,NAT网络地址转换,家庭网 3,host only 只能和宿主电脑打交道 Linux命令形式 命令 +[参数]+ ...

  7. python爬虫——用selenium爬取京东商品信息

    1.先附上效果图(我偷懒只爬了4页)  2.京东的网址https://www.jd.com/ 3.我这里是不加载图片,加快爬取速度,也可以用Headless无弹窗模式 options = webdri ...

  8. netcore 下的policy授权自定义返回结果

    目前一直在用policy做权限校验,但是好像组里需要将返回结果统一,之前用的都是直接继承AuthorizationHandler然后调用context.Fail(),但是这样会导致没办法自定义返回结果 ...

  9. Git (一)预设环境和免密登录

    背景 一直用的svn,这段时间换了之后才发现git的强大功能.缺点就是可能上手比较难一点. 接下来就带你Git入门 Git是什么? Git是目前世界上最先进的分布式版本控制系统 Git有什么特点?好用 ...

  10. 数据库SQL---数据库、基本表、视图、索引的定义、修改、删除

    1.SQL(结构化查询语言)的组成:数据定义语言DDL.数据操纵语言DML.数据控制语言DCL.其他. 2.SQL语言的功能: 1)数据查询:SELECT 2)数据定义:CREATE   DROP  ...