1. 程式人生 > >POJ 1009不算解題報告的解題報告

POJ 1009不算解題報告的解題報告

    好久沒有寫poj的題了,一定要堅持下來。畢竟是要寫寫程式碼為生的,演算法的重要性不言而喻。1009這道題已經糾結了很久了,其實題目不難,看到後思路也很直觀,就是考慮到同一個數字跨過三行以上時,中間部分肯定就可以不用計算,直接為零。之前覺得可以建立一個map,當包括中間值在內的9個數組成的陣列之前已經算過的話,直接輸出map的value就可以了。不過似乎這樣每次搜尋、比較,效率反而低了。另外,寫的時候想著如果輸入的資料比較多,它們的個數之和可能會超過int範圍,看來是我多想了。

    這道題總算硬著頭皮“看”完了。自己嘗試了幾遍都沒有完成,最後還是看了大牛的解題報告。所以其實自己也沒有寫完。在這裡總結一下,希望有提高。

    寫程式的時候按照框架寫,先想好要分幾部分,然後再擴充每部分的細節內容。這道不難的題,我一開始就被細節部分弄的一點信心也沒有了。

   c++ code:

1009 Accepted 228K 16MS C++ 4691B
#include <stdio.h>
#include <assert.h>
 
int n, t, k;
int num[2000], sum[2000], digit[2000], ansdigit[5000], ansnum[5000];
//求絕對值函式,可以用math中的同名函式
int abs(int x)
{
  if (x < 0) return -x;
  return x;
}
//迴圈變數i和周圍元素位置對映
/*****
*0 1 2
*3   4
*5 6 7
******/
inline int map(int c, int now)
{
  switch (c)
  {
    case 0: return now - t - 1;
    case 1: return now - t;
    case 2: return now - t + 1;
    case 3: return now - 1;
    case 4: return now + 1;
    case 5: return now + t - 1;
    case 6: return now + t;
    case 7: return now + t + 1;
  }
  assert(false);
  return -1;
}
//算出位置y的元素值,這裡forward很巧妙,為0向前找,為1向後找
int number(int c, int y, bool forward)
{
  int i;
  if (forward)
  {
    for (i = c; i <= n; ++i)
      if (sum[i] >= y) break;
    return i;
  }
  else
  {
    for (i = c; i > 0; --i)
      if (sum[i] < y) break;
    return i+1;
  }
}
//判斷邊界情況 
bool ok(int now, int i)
{
  if (now < t && (i == 1 || i == 0 || i == 2)) return false;//起始行的前一行
  if (now > sum[n] - t && (i == 6 || i == 5 || i == 7)) return false;//結束行的後一行
  if (now % t == 1 && (i == 0 || i == 3 || i == 5)) return false;//左邊一行的左邊
  if (now % t == 0 && (i == 2 || i == 4 || i == 7)) return false;//右邊一行的右邊
  return true;
}
//比較與周圍8個元素之差的絕對值大小
int get(int x, int now)
{
  int i, max = 0, m;
  for (i = 0; i < 8; ++i)
  {
    m = map(i, now);
    if (ok(now, i) && m > 0 && m <= sum[n])
    {
      m = number(x, m, i / 4);
      if (max < abs(digit[x] - digit[m])) max = abs(digit[x] - digit[m]);
    }
  }
  return max;
}
//減少重複計算 
int late(int x, int now, int r)
{
    int p;
    if (r <= now) return 1;
    if (now % t != 1)
    {
        if (digit[number(x, now - 1, 0)] != digit[x]) return 1;
        if (now > t)
        {
            p = number(x, now - t - 1, 0);
            if ((sum[p] - 1) / t < (now - 1) / t)
            {
              if (sum[p] <= now - t + 1) return 1;
              if (r > sum[p] - 1 + t) r = sum[p] - 1 + t;
            }
        }
        if (now <= sum[n] - t)
        {
            p = number(x, now + t - 1, 1);
            if ((sum[p] - 1) / t == (now - 1) / t + 1)
            {
              if (sum[p] <= now + t + 1) return 1;
              if (r > sum[p] - 1 - t) r = sum[p] - 1 - t;
            }
        }
        return r - now + 1;
    }
    else
    {
        if (now > t)
        {
            p = number(x, now - t, 0);
            if ((sum[p] - 1) / t < (now - 1) / t)
            {
              if (sum[p] <= now - t + 1) return 1;
              if (r > sum[p] - 1 + t) r = sum[p] - 1 + t;
            }
        }
        if (now <= sum[n] - t)
        {
            p = number(x, now + t, 1);
            if ((sum[p] - 1) / t == (now - 1) / t + 1)
            {
              if (sum[p] <= now + t + 1) return 1;
              if (r > sum[p] - 1 - t) r = sum[p] - 1 - t;
            }
        }
        return r - now + 1;
    }
}
//程式的主體部分,計算start和end之間的部分。這段程式實際上是個遞迴,多行的情況可以歸約到start和end在同一行的情況
void make(int x, int start, int end)
{
  int i, r;
  int a = (start - 1) / t, b = (end - 1) / t;
  if (a != b)//如果不在同一行
  {
    make(x, start, b * t);//歸約
    make(x, b * t + 1, end);//同一行的情況
    return;
  }
  //通過get函式算出最大的絕對值,儲存在last中,the儲存當前位置算出的最大絕對值。如果兩者相同,就要進行合併
  int last = get(x, start), sum = 0, the;
  for (i = start; i <= end;)
  {
    the = get(x, i);
    r = late(x, i, end - 1);
    if (the == last)
      sum += r;//合併
    else
    {
      ansdigit[++k] = last;
      ansnum[k] = sum;
      sum = r;
      last = the;
    }
    i += r;
  }
  ansdigit[++k] = last;
  ansnum[k] = sum;
}
int main()
{
  int i, x, y;
  sum[0] = 0;
  while (scanf("%d", &t) && t)
  {
    i = 0;
    k = 0;
    while (scanf("%d%d", &x, &y) && (x || y))
    {
      digit[++i] = x; //digit陣列儲存輸入元素
      num[i] = y;//num陣列儲存元素個數
      sum[i] = sum[i - 1] + num[i];//sum陣列記錄元素個數和,主要用於判斷元素i的周圍8個元素是什麼
    }
    n = i;
    for (i = 1; i <= n; ++i)
    {
      if (num[i] <= t + t + 2)//不存在同一個元素跨越3行的情況
        make(i, sum[i - 1] + 1, sum[i]);
      else
      {
        make(i, sum[i - 1] + 1, sum[i - 1] + t + 1);//前面部分同if部分
        ansdigit[++k] = 0;//中間直接為0
        ansnum[k] = num[i] - 2 * t - 2;//0的個數
        make(i, sum[i] - t, sum[i]);//後面部分也需要計算
      }
    }
    printf("%d\n", t);//輸出開始
    for (i = 1; i <= k;)
    {
      int outdigit = ansdigit[i];
      int outnum = 0;
      while (i <= k && ansdigit[i] == outdigit)//如果相鄰元素相同,需要合併
        outnum += ansnum[i++];
      printf("%d %d\n", outdigit, outnum);
    }
    printf("0 0\n");
  }
  printf("0\n");
}


相關推薦

POJ 1009解題報告解題報告

    好久沒有寫poj的題了,一定要堅持下來。畢竟是要寫寫程式碼為生的,演算法的重要性不言而喻。1009這道題已經糾結了很久了,其實題目不難,看到後思路也很直觀,就是考慮到同一個數字跨過三行以上時,中間部分肯定就可以不用計算,直接為零。之前覺得可以建立一個map,當包括中

POJ 1009 Edge Detection解題報告

解決該題的核心思想是:只計算包括變化點的9個點的值。設輸入影象為(v0, r0), (v1, r1), ..., (vn, rn), 那麼變化點為v0, v1, ..., vn。這些點的值計算出來後,後面的輸出就好說。但這樣的計算還是不夠的,我只是找出了以下3種特殊情況,處

POJ 1915(BFS_D題)解題報告

題目 pan 位置 open con play def sta 鏈接 題目鏈接:http://poj.org/problem?id=1915 -------------------------------------------------------- 題意:Chess中

POJ 1958 Strange Towers of Hanoi 解題報告

tran span lin line 移動 意思 公式 ron mat Strange Towers of Hanoi 大體意思是要求\(n\)盤4的的hanoi tower問題。 總所周知,\(n\)盤3塔有遞推公式\(d[i]=dp[i-1]*2+1\) 令\(f[i]

[poj 2480] Longge's problem 解題報告 (歐拉函數)

ios ons src names def ref 技術 esp ++ 題目鏈接:http://poj.org/problem?id=2480 題目大意: 題解: 我一直很欣賞數學題完美的復雜度 #include<cstring> #inc

POJ 2528 Mayor's posters 解題報告(C++)

題目連結:http://poj.org/problem?id=2528 簡單線段樹離散化..... #include <cstdio> #include <vector> #include <algorithm> #include <mem

poj 3255 Roadblocks 次短路 spfa 解題報告

Bessie has moved to a small farm and sometimes enjoys returning to visit one of her best friends. She does not want to get to her old home too quickly, be

法題解題思路及代碼(定時更新)

希望 target 解答 時間 -s 一次 return 時間復雜度 2.3 畢業半年, 平時工作總是關註業務、架構,而卻越來越少關註性能, 也再也沒有做過任何涉及算法的工作了希望有時間把這些拉下的東西拾起來,畢竟不論是使用什麽語言,從事什麽行業,只要是程序員,算法才是真正

POJ 1009--Edge Detection解題思路

題意 使用一種叫做“run length encoding”的方式來儲存大尺寸圖片,該方法是通過記錄編碼值和編碼長度的對(value,length)來儲存圖片。有一種簡單的edge detection演算法是將影象中的每一個點的值與他周圍的八個點求差,然後取絕

Oracle與集器對比測試報告

1.測試目的 針對相同的硬體環境和計算任務,對比Oracle和集算器的效能差異,為客戶選型提供參考。 2.硬體環境 裝置數量:1臺 CPU:16核 Intel(R) Xeon(R) CPU E5620  @ 2.40GHz 記憶體:20G 3.軟體環境 作業系統:CentOS6.4 64位 JDK:1.6

緣起,浪漫的故事

就會 證明 無奈 只知道 歲月 也說 但我 軟件工程 放棄 一:起源,故事的開始 或許,很多年以後我依舊會問自己同樣的問題。為何會來到這裏來學習一個我未曾了解的專業?目前的我也許會說這是沒辦法的事,是當初在自己選擇的時候的一個失誤。回過去看當時,用了大量的時間去做選擇。那時

Git程序員的必備技能?

Git Coding 程序員 點擊關註 異步圖書,置頂公眾號每天與你分享 IT好書 技術幹貨 職場知識參與文末話題討論,每日贈送異步圖書。——異步小編Git的背後有著一個非常精彩的成功故事。2005年4月,Linus Torvalds因不滿當時任何一個可用的開源版本控制系統,就親自著手實現了Git

身為手機系統霸主,安卓對於谷歌來說成功?

身為手機系統霸主安卓對於谷歌來說算不算先來說一下,在當前的智能手機操作系統中安卓和iOS可謂獨大,占據了九成多的市場份額。但因為iOS只在蘋果設備上使用,安卓系統卻因開放性而遍地開花,相對而言安卓系統更加強勢。根據statista統計,從2009年第一季度到2017年第二季度,安卓系統的全球用戶占有率從1.6

我也知道這bug了,單純記錄,沒別的意思,圖片是上傳在慕課網的,所以預覽了。。0.0

。。 https ref 讓我 chrom ron 允許 error 個人 無意發現慕課網修改個人簽名功能性bug 修改個人簽名失敗的問題 圖片 經過測試,像這樣兩行文字中間有換行的話,保存會提示error,如圖: 圖片 而如果不換行,就能成功: 圖片 圖片 瀏覽器用的Ch

朱曄和你聊Spring系列S1E4:靈活但好用的Spring MVC

iat ndt css host 4.0 ttr found zip壓縮 return 本文會以一些例子來展現Spring MVC的常見功能和一些擴展點,然後我們來討論一下Spring MVC好用不好用。 使用SpringBoot快速開始 基於之前的parent模塊,我

程式設計或者軟體開發到底知識?

自動上次看了業界大神阮一峰發的那篇文章之後,給我的印象非常的深刻,一直想寫文章跟大家交流和探討一下,那就是:軟體開發到底算不算知識呢? 在探討這個話題之前,我們先看看大神阮一峰是怎麼說的,大致內容如下: 在軟體開發中,技術變化如此之快,你花費了大量時間學習技術和工具,一旦這些技術被取代,你的知識將變

2018最牛Python指令碼!!!秒搶紅包!還能無視撤回訊息!!!

曾經有一份"份額很足"的大紅包,擺在我面前,我沒有好好珍惜,如果上天再給我一次機會,我會對發紅包的人說三個字:再來個。如果要在這個紅包的金額上面加個上限,我希望是200。(因為微信紅包最大的紅包就是200) 我想很多的朋友都遇到過這樣的問題,特別是在親友群裡面,很多時候別人發了紅包自己卻不

DevOps基礎-6.2-提前結束:現在一個DevOps工程師

本來繼續翻譯第六章節,第六章節主要介紹的是運維的理論和一些很有效的策略。但是,發現感覺這些也用處不大。就沒有繼續翻譯的動力了。差不多25篇文章來介紹DevOps的文化和一些常識,術語,其中持續整合(CI)和持續交付(CD)顯然就是DevOps的核心部分。DevOps這個話題很大,包含技術很廣。不

#華為程式設計師70萬年薪,但還想跳槽去大廠,網友:華為大廠?

如今網際網路行業無疑是高薪行業之一,基本各類工科行業也能排前幾,很多人都想做個程式設計師,但是就網際網路企業來說無疑是bat最好,不僅能給自己鍍金,也能學技術,薪資也都還可以,哪怕以後想要跳槽也能有個好去處。 如果有想學習java的程式設計師,可來我們的java學習扣qun:72340,39

hexo的next主題部落格中加入分類頁面的js,實現多級目錄,並且能夠點選展開,隱藏下級目錄~(知道深度優化~~~)

多級標題 在自己的xxxx.md檔案中做如下修改: categories: - 搗蛋鬼 - mac 新建catogery_js.js(名字無所謂) 加入自己的js 我這裡是下面這樣的 function category_js () { $("&