PAT Basic 1068. 萬綠叢中一點紅(20)(C語言實現)

我的PAT系列文章更新重心已移至Github,歡迎來看PAT題解的小伙伴請到Github Pages瀏覽最新內容。此處文章目前已更新至與Github Pages同步。歡迎star我的repo

題目

對于計算機而言,顏色不過是像素點對應的一個 24 位的數值。現給定一幅分辨率為 M\times N
的畫,要求你找出萬綠叢中的一點紅,即有獨一無二顏色的那個像素點,并且該點的顏色與其周圍 8 個相鄰像素的顏色差充分大。

輸入格式:

輸入第一行給出三個正整數,分別是 MN\le 1000),即圖像的分辨率;以及 TOL,是所求像素點與相鄰點的顏色差閾值,色差超過
TOL 的點才被考慮。隨后 N 行,每行給出 M 個像素的顏色值,范圍在 [0, 2^{24}) 內。所有同行數字間用空格或 TAB 分開。

輸出格式:

在一行中按照 (x, y): color 的格式輸出所求像素點的位置以及顏色值,其中位置 xy 分別是該像素在圖像矩陣中的列、行編號(從
1 開始編號)。如果這樣的點不唯一,則輸出 Not Unique;如果這樣的點不存在,則輸出 Not Exist

輸入樣例 1:

8 6 200
0    0    0        0        0        0        0        0
65280    65280    65280    16711479 65280    65280    65280    65280
16711479 65280    65280    65280    16711680 65280    65280    65280
65280    65280    65280    65280    65280    65280    165280   165280
65280    65280    16777015 65280    65280    165280   65480    165280
16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215

輸出樣例 1:

(5, 3): 16711680

輸入樣例 2:

4 5 2
0 0 0 0
0 0 3 0
0 0 0 0
0 5 0 0
0 0 0 0

輸出樣例 2:

Not Unique

輸入樣例 3:

3 3 5
1 2 3
3 4 5
5 6 7

輸出樣例 3:

Not Exist

思路

在這道題上我好像想多了,當然也有可能陳越姥姥想少了(怎么可能,不可能的)。

首先就是,“顏色差” 是什么?網上其他人的做法99%(可能100%)都是直接把兩個顏色的值相減,結果的整數就是顏色差了。
而我參考了Wiki: Color difference
將(R, G, B)三維顏色空間的“距離”作為顏色差,這也是很合理的。比如65280,也就是#00FF00,是綠色,
而65279,#00FEFF,是青色,兩者在整數大小上相差1,但是顏色有很大區別。幸好(或許也是不幸)在測試用例沒有使用上面這樣的例子,
我的測試結果和大家都是一樣的。

然后就是大家都遇到的難(keng)點:

  • 第一個難(keng)點:

要求你找出萬綠叢中的一點紅,即有獨一無二顏色的那個像素點

解讀:需要這個顏色在整幅圖中只出現一次。

  • 第二個難(keng)點:雖然題目說

該點的顏色與其周圍8個相鄰像素的顏色差充分大。

但是題目還是設置了處于邊界的滿足“條件”的點,所以說這又是一個題目敘述不清楚的案例(好多受害者)。

應對這個問題目前看到的代碼中有兩個解決方案,一是加入邊界特殊情況的檢測,二是在題目數據的周圍加一圈0。
第一個方案沒有問題。第二個方案我覺得是有問題的,如圖片的左上角有這樣的數據:

#000001 #0000FF ......
#0000FF #0000FF ......
......  ......  ......

假設顏色#000001在圖片只出現了這一次,這樣這個點應該符合要求。但是周圍加上0就變成了

#000000 #000000 #000000 ......
#000000 #000001 #0000FF ......
#000000 #0000FF #0000FF ......
......  ......  ......  ......

不管顏色差是怎么算的,這個中間的#000001都是不能被檢測出來的。但是又很幸運地,我看使用這個方法的代碼也都通過了。
我能說什么呢 :)

P.S.

關于代碼優化:這個代碼運行時間好長(160+ms),應該是判斷顏色唯一太耗時了,相當于O(N2*M2),
或許改為用另一個排序好的列表查找會好很多(預計時間復雜度為M*N*log(M*N))。

更新:上面的判斷竟然是錯的,我在本地測試了上述方案,使用最多的數據1000*1000,排序加查找竟然比原來的方案耗時多一個數量級
~~~o(>﹏<)o。之前的方案從文件讀取用了0.2秒,但是查找只用了0.04秒(其中iUnique函數只有0.02秒!)。
新的方案qsort用了0.2秒,查找(使用了bsearch)用了0.3秒!這不科學 (ㄒoㄒ) (難道是被stdlib坑了?)
(證明瓶頸在數據讀取上,那運行時間長的鍋我就不背了)

代碼

最新代碼@github,歡迎交流

#include <stdio.h>

#define SQR(X) ((X)*(X))
#define R(COLOR) ((COLOR & 0XFF0000) >> 16)
#define G(COLOR) ((COLOR & 0X00FF00) >> 8)
#define B(COLOR) (COLOR & 0X0000FF)
#define D(C1, C2) (SQR(R(C1) - R(C2)) + SQR(G(C1) - G(C2)) +  SQR(B(C1) - B(C2)))

int iUnique(int array[][1000], int x, int y, int x0, int y0)
{
    for(int i = 0; i < x; i++)
        for(int j = 0; j < y; j++)
            if(array[i][j] == array[x0][y0] && !(i == x0 && j == y0))
                return 0;
    return 1;
}

int main()
{
    int M, N, TOL;
    scanf("%d %d %d", &M, &N, &TOL);

    int fig[1000][1000];
    for(int i = 0; i < N; i++)
        for(int j = 0; j < M; j++)
            scanf("%d", &fig[i][j]);

    int count = 0, M0, N0;
    for(int i = 0; i < N; i ++)
        for (int j = 0; j < M; j++)
            if((i > 0 && j > 0 ? D(fig[i][j], fig[i - 1][j - 1]) > SQR(TOL) : 1)
            && (i > 0          ? D(fig[i][j], fig[i - 1][j    ]) > SQR(TOL) : 1)
            && (i > 0 && j < M ? D(fig[i][j], fig[i - 1][j + 1]) > SQR(TOL) : 1)
            && (         j > 0 ? D(fig[i][j], fig[i    ][j - 1]) > SQR(TOL) : 1)
            && (         j < M ? D(fig[i][j], fig[i    ][j + 1]) > SQR(TOL) : 1)
            && (i < N && j > 0 ? D(fig[i][j], fig[i + 1][j - 1]) > SQR(TOL) : 1)
            && (i < N          ? D(fig[i][j], fig[i + 1][j    ]) > SQR(TOL) : 1)
            && (i < N && j < M ? D(fig[i][j], fig[i + 1][j + 1]) > SQR(TOL) : 1)
            && iUnique(fig, N, M, i, j))
            {
                count++;
                N0 = i;
                M0 = j;
            }

    if(count == 0)  printf("Not Exist");
    if(count == 1)  printf("(%d, %d): %d", M0 + 1, N0 + 1, fig[N0][M0]);
    if(count >= 2)  printf("Not Unique");

    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容