【轉(zhuǎn)】imos-累積和法(原文修正)

原文轉(zhuǎn)自:http://www.hankcs.com/program/algorithm/imos_method.html
但原文示例有誤,應(yīng)修改為一下:

在“怪物地圖”的例子中思想與代碼有誤,應(yīng)改為:左上角+1卡睦,右上角右側(cè)-1本慕,左下角下方-1踏堡,右下角右下方+1碌燕;若超出tiles則沒(méi)有+1或-1折汞;根據(jù)圖示倔幼,怪物種類(lèi)應(yīng)該是3種,坐標(biāo)應(yīng)該為:

    // 左下角坐標(biāo)
    int b[] = {3,4,5};
    int c[] = {0,1,2};
    // 右上角坐標(biāo)
    int a[] = {0,3,2};
    int d[] = {3,2,5};

修改后代碼為

public void monsterMap() {
    int h=6;
    int w=6;
    int n=3;

    // 左下角坐標(biāo)
    int b[] = {3,4,5};
    int c[] = {0,1,2};
    // 右上角坐標(biāo)
    int a[] = {0,3,2};
    int d[] = {3,2,5};

    int[][] tiles = new int[h][w];
    //影響力
    for (int i = 0; i < n; i++) {
        setTiles(tiles, a[i], c[i], +1);
        setTiles(tiles, b[i]+1, d[i]+1, +1);
        setTiles(tiles, a[i], d[i]+1, -1);
        setTiles(tiles, b[i]+1, c[i], -1);
    }
    //橫向累加
    for (int i = 0; i < h; i++) {
        for (int j = 1; j < w; j++) {
            tiles[i][j] += tiles[i][j-1];
        }
    }
    //縱向累加
    for (int i = 0; i < w; i++) {
        for (int j = 1; j < h; j++) {
            tiles[j][i] += tiles[j-1][i];
        }
    }
    //查詢(xún)最大值
    int max=0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            max = Math.max(tiles[i][j], max);
        }
    }
    System.out.println(max);

}

private void setTiles(int[][] tiles, int h, int w, int v) {
    if (h >= tiles.length || w >= tiles[h].length) {
        return ;
    }
    tiles[h][w] = v;
}

以下為原文部分


在解AOJ 0531 Paint Color時(shí)爽待,學(xué)到了一個(gè)累積和的妙用——imos法损同,由于原文是日語(yǔ),所以特意翻譯過(guò)來(lái)鸟款。值得一提的是膏燃,作者Kentaro Imajo跟鄙人同齡,卻已取得如此多的成就何什,而鄙人一無(wú)所成蹄梢,實(shí)在汗顏。

imos法

imos法是將累積和算法拓展到多次元富俄、高次空間的方法。雖然程序競(jìng)賽中出題最多不過(guò)2次元1次而咆,但是2012年Kentaro Imajo將其用于高次元高次空間霍比,在信號(hào)處理/圖像處理領(lǐng)域取得了成就。

基礎(chǔ)imos法

最簡(jiǎn)單的imos法是1次元0次系數(shù)的求解思想暴备。如圖悠瞬,有三個(gè)俄羅斯方塊在一起,懸空的部分會(huì)掉下去,求從左到右的高度浅妆?這個(gè)高度就是橫坐標(biāo)固定時(shí)望迎,上面矩形高度之和。這就是最簡(jiǎn)單的imos法凌外。

image

例題

你在經(jīng)營(yíng)一個(gè)咖啡廳辩尊,你的咖啡廳里每個(gè)客人在S_i時(shí)刻進(jìn)店,E_i時(shí)刻出店康辑。求店里最多有多少客人摄欲?(客人最多C個(gè),時(shí)刻在T內(nèi)疮薇。如果有多人同時(shí)進(jìn)店出店胸墙,先算出店的人)。

樸素的解法

樸素的思想是按咒,計(jì)算每個(gè)時(shí)刻客戶(hù)的數(shù)量迟隅,從中找出最大值。但是励七,復(fù)雜度是O(CT)

1.  #include <iostream>
2.  #include <algorithm>
3.  using namespace std;

5.  #define C 4
6.  #define T 10
7.  // 每個(gè)客人的進(jìn)入時(shí)間
8.  int S[C] = { 1, 3, 5, 7 };
9.  // 每個(gè)客人的離開(kāi)時(shí)間
10.  int E[C] = { 2, 8, 6, 8 };
11.  // 店里的人數(shù)
12.  int table[T];

14.  ///////////////////////////SubMain//////////////////////////////////
15.  int main(int argc, char *argv[])
16.  {
17.  memset(table, 0, sizeof(table));
18.  for (int i = 0; i < C; i++) 
19.  {
20.  // 從時(shí)間 S[i] 到 E[i] - 1 店里人數(shù)計(jì)數(shù)加一
21.  for (int j = S[i]; j < E[i]; j++) 
22.  {
23.  table[j]++;
24.  }
25.  }
26.  // 找最大値
 27.  cout<< *max_element(table, table + T) << endl;
28.  system("pause");
29.  return 0;
30.  }
31.  ///////////////////////////End Sub//////////////////////////////////

imos法解法

imos法的基本方向是智袭,只統(tǒng)計(jì)出入店時(shí)刻的人數(shù)變化(我個(gè)人理解相當(dāng)于求導(dǎo)),入店+1呀伙,出店-1补履。最終統(tǒng)計(jì)的時(shí)候,需要將每個(gè)時(shí)刻加上前一個(gè)時(shí)刻的統(tǒng)計(jì)量(我個(gè)人理解相當(dāng)于求積分)剿另,其中的最大值就是所求箫锤。記錄復(fù)雜度O(C),累加復(fù)雜度O(T)雨女,所以整體復(fù)雜度O(C+T)谚攒。

1.  #include <iostream>
2.  #include <algorithm>
3.  using namespace std;

5.  #define C 4
6.  #define T 10
7.  // 每個(gè)客人的進(jìn)入時(shí)間
8.  int S[C] = { 1, 3, 5, 7 };
9.  // 每個(gè)客人的離開(kāi)時(shí)間
10.  int E[C] = { 2, 8, 6, 8 };
11.  // 店里的人數(shù)
12.  int table[T];

14.  ///////////////////////////SubMain//////////////////////////////////
15.  int main(int argc, char *argv[])
16.  {
17.  memset(table, 0, sizeof(table));
18.  for (int i = 0; i < C; i++) 
19.  {
20.  table[S[i]]++;  // 入店+1
21.  table[E[i]]--;  // 出店-1
22.  }
23.  // 累加
24.  for (int i = 1; i < T; i++) 
25.  {
26.  table[i] += table[i - 1];
27.  }
28.  // 找最大値
29.  cout<< *max_element(table, table + T) << endl;
30.  system("pause");
31.  return 0;
32.  }
33.  ///////////////////////////End Sub//////////////////////////////////

推廣到二次元

imos相對(duì)于樸素方法的一個(gè)優(yōu)點(diǎn)就是隨著次元增大復(fù)雜度的降低越明顯。

例題

你在玩一個(gè)抓怪獸的游戲氛堕,現(xiàn)在你面前是一張W*H的地圖馏臭,地圖里有N種怪物。怪物i只會(huì)在左下角為(B_i,C_i)讼稚,右上角為(A_i,D_i)的矩形區(qū)域內(nèi)出現(xiàn)括儒。求單位區(qū)域內(nèi)最多有多少種怪獸?

image

樸素解法

樸素的解法就是計(jì)算每一個(gè)單位區(qū)域內(nèi)出現(xiàn)的怪獸數(shù)锐想,然后找出最大值帮寻。復(fù)雜度是O(NWH)。

1.  #include <iostream>
2.  #include <algorithm>
3.  using namespace std;
4.  #define  W  6
5.  #define  H  6
6.  #define  N  4
7.  // 左下角坐標(biāo)
8.  int B[N] = {3,4,3,5,};
9.  int C[N] = {0,1,2,2,};
10.  // 右上角坐標(biāo)
11.  int A[N] = {0,3,2,2,};
12.  int D[N] = {3,2,3,5,};
13.  // 地圖上的分布結(jié)果
14.  int tiles[H][W];

16.  ///////////////////////////SubMain//////////////////////////////////
17.  int main(int argc, char *argv[])
18.  {
19.  memset(tiles, 0, sizeof(tiles));
20.  for (int i = 0; i < N; i++) 
21.  {
22.  // 怪獸 i 出現(xiàn)的范圍 [(A[i],C[i]), (B[i],D[i])) 內(nèi)的計(jì)數(shù)加一
23.  for (int y = C[i]; y < D[i]; y++) 
24.  {
25.  for (int x = A[i]; x < B[i]; x++) 
26.  {
27.  tiles[y][x]++;
28.  }
29.  }
30.  }
31.  // 求最大値
32.  cout<< *max_element(tiles[0], tiles[0] + H * W) << endl;
33.  system("pause");
34.  return 0;
35.  }
36.  ///////////////////////////End Sub//////////////////////////////////

imos法解法

此例思想與代碼有誤,修改方法見(jiàn)文字開(kāi)頭

矩形的左上角 (A[i],C[i]) +1 赠摇,右上角 (A[i],D[i]) ?1固逗,左下角 (B[i],C[i]) ?1 浅蚪,右下角(B[i],D[i]) +1 ,統(tǒng)計(jì)最終結(jié)果之前累加烫罩。加一減一 O(N)惜傲,累加(WH) 整體復(fù)雜度 O(N+WH) 。

1.  #include <iostream>
2.  #include <algorithm>
3.  using namespace std;
4.  #define  W  6
5.  #define  H  6
6.  #define  N  4
7.  // 左下角坐標(biāo)
8.  int B[N] = {3,4,3,5,};
9.  int C[N] = {0,1,2,2,};
10.  // 右上角坐標(biāo)
11.  int A[N] = {0,3,2,2,};
12.  int D[N] = {3,2,3,5,};
13.  // 地圖上的分布結(jié)果
14.  int tiles[H][W];

16.  ///////////////////////////SubMain//////////////////////////////////
17.  int main(int argc, char *argv[])
18.  {
19.  memset(tiles, 0, sizeof(tiles));
20.  // 影響力計(jì)算 (圖 3)
21.  for (int i = 0; i < N; i++) 
22.  {
23.  tiles[C[i]][A[i]]++;
24.  tiles[C[i]][B[i]]--;
25.  tiles[D[i]][A[i]]--;
26.  tiles[D[i]][B[i]]++;
27.  }
28.  // 橫向累積和 (圖 4, 5)
29.  for (int y = 0; y < H; y++) 
30.  {
31.  for (int x = 1; x < W; x++) 
32.  {
33.  tiles[y][x] += tiles[y][x - 1];
34.  }
35.  }
36.  // 縱向累積和 (圖 6, 7)
37.  for (int y = 1; y < H; y++) 
38.  {
39.  for (int x = 0; x < W; x++) 
40.  {
41.  tiles[y][x] += tiles[y - 1][x];
42.  }
43.  }

45.  cout<< *max_element(tiles[0], tiles[0] + H * W) << endl;
46.  system("pause");
47.  return 0;
48.  }
49.  ///////////////////////////End Sub//////////////////////////////////
image

圖三:影響力計(jì)算

image

圖四:橫向累加

image

圖五:橫向累加結(jié)果

image

圖六:縱向累加

image

圖七:縱向累加結(jié)果

更高級(jí)的用法

暫時(shí)用不到贝攒,記錄一個(gè)地址盗誊,有空再看。

Reference

http://imoz.jp/algorithms/imos_method.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饿这,一起剝皮案震驚了整個(gè)濱河市浊伙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌长捧,老刑警劉巖嚣鄙,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異串结,居然都是意外死亡哑子,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)肌割,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卧蜓,“玉大人,你說(shuō)我怎么就攤上這事把敞∶旨椋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵奋早,是天一觀的道長(zhǎng)盛霎。 經(jīng)常有香客問(wèn)我,道長(zhǎng)耽装,這世上最難降的妖魔是什么愤炸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮掉奄,結(jié)果婚禮上规个,老公的妹妹穿的比我還像新娘。我一直安慰自己姓建,他們只是感情好诞仓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著速兔,像睡著了一般狂芋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上憨栽,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼屑柔。 笑死屡萤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掸宛。 我是一名探鬼主播死陆,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼唧瘾!你這毒婦竟也來(lái)了措译?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饰序,失蹤者是張志新(化名)和其女友劉穎领虹,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體求豫,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡塌衰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蝠嘉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片最疆。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蚤告,靈堂內(nèi)的尸體忽然破棺而出努酸,到底是詐尸還是另有隱情,我是刑警寧澤杜恰,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布获诈,位于F島的核電站,受9級(jí)特大地震影響箫章,放射性物質(zhì)發(fā)生泄漏烙荷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一檬寂、第九天 我趴在偏房一處隱蔽的房頂上張望终抽。 院中可真熱鬧,春花似錦桶至、人聲如沸昼伴。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)圃郊。三九已至,卻和暖如春女蜈,著一層夾襖步出監(jiān)牢的瞬間持舆,已是汗流浹背色瘩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逸寓,地道東北人居兆。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像竹伸,于是被迫代替她去往敵國(guó)和親泥栖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容