poj 2812 惱人的青蛙(列舉 剪枝)

2021-07-11 18:15:10 字數 3197 閱讀 5098

程式設計實習列舉練習 poj 2812 惱人的青蛙(列舉+剪枝)

總時間限制: 2000ms 單個測試點時間限制: 500ms 記憶體限制: 65536kb

描述 在南韓,有一種小的青蛙。每到晚上,這種青蛙會跳越稻田,從而踩踏稻子。農民在早上看到被踩踏的稻子,希望找到造成最大損害的那只青蛙經過的路徑。每只青蛙總是沿著一條直線跳越稻田,而且每次跳躍的距離都相同。

如下圖所示,稻田裡的稻子組成乙個柵格,每棵稻子位於乙個格點上。而青蛙總是從稻田的一側跳進稻田,然後沿著某條直線穿越稻田,從另一側跳出去

如下圖所示,可能會有多隻青蛙從稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,將這棵水稻拍倒。有些水稻可能被多隻青蛙踩踏。當然,農民所見到的是圖4中的情形,並看不到圖3中的直線,也見不到別人家田裡被踩踏的水稻。

根據圖4,農民能夠構造出青蛙穿越稻田時的行走路徑,並且只關心那些在穿越稻田時至少踩踏了3棵水稻的青蛙。因此,每條青蛙行走路徑上至少包括3棵被踩踏的水稻。而在一條青蛙行走路徑的直線上,也可能會有些被踩踏的水稻不屬於該行走路徑

①不是一條行走路徑:只有兩棵被踩踏的水稻;

②是一條行走路徑,但不包括(2,6)上的水道;

③不是一條行走路徑:雖然有3棵被踩踏的水稻,但這三棵水稻之間的距離間隔不相等。

請你寫乙個程式,確定:在一條青蛙行走路徑中,最多有多少顆水稻被踩踏。例如,圖4的答案是7,因為第6行上全部水稻恰好構成一條青蛙行走路徑。

輸入 從標準輸入裝置上讀入資料。第一行上兩個整數r、c,分別表示稻田中水稻的行數和列數,1≤r、c≤5000。第二行是乙個整數n,表示被踩踏的水稻數量, 3≤n≤5000。在剩下的n行中,每行有兩個整數,分別是一顆被踩踏水稻的行號(1~r)和列號(1~c),兩個整數用乙個空格隔開。而且,每棵被踩踏水稻只被列出一次。

輸出 從標準輸出裝置上輸出乙個整數。如果在稻田中存在青蛙行走路徑,則輸出包含最多水稻的青蛙行走路徑中的水稻數量,否則輸出0。

樣例輸入

6 7

14 2 1

6 6

4 2

2 5

2 6

2 7

3 4

6 1

6 2

2 3

6 3

6 4

6 5

6 7

樣例輸出

7**

poj 1054

注意本題為了降低空間複雜度,不可以直接儲存下地圖,可以只存青蛙的位置,這樣一來為了方便查詢,必然要使用排序與二分查詢,為了能使用庫函式qsort()與bsearch(),必須編寫函式指標compare(),以x作為第一關鍵字。

注意compare格式為(int*) (const void * e1,const void * e2 ),qsort()與bsearch()引數可以看ide的提示。

而bsearch()返回值為void * 應該使用如下強制型別轉化語句 p=(type *) bsearch()。

這就實現了二分查詢,大大降低了查詢代價,也保證了資料的有序性。

列舉前兩步落腳點i,j。

接下來要考慮列舉順序,為了減少一條路線重複被列舉,可以規定列舉順序,如果反向一步沒有踏出田野就停止列舉該情況。

再考慮提前終止不可能產生更優解的路線,具體為,該情況步長在當前最大值步數下是會出田野,提前終止這一情況,但是有乙個細微(sophisticated)的點要考慮,就是如果出田野是因為x分量出邊界,那麼列舉以後的j對應的x步長只會越來越長,還會出界,故不必列舉接下來的j,直接跳到下乙個i,可以break,反之如果因為y分量出邊界,只能列舉以下的j,即只可以continue。

這個優化的思路充分利用了當前已知的最大值答案與儲存列舉結構的單調性質,這個優化幾乎使得列舉的第二個維度在一定計算後幾乎退化,使得本來超時的演算法能在20ms內ac,這個技巧看似平常優化力度不大但是效果顯著,其中微妙之處值得回味。

384kb 20ms 1683 b g++

#define max_n 5000

#include

#include

struct point_type

;int r,c,n,ans=2,dx,dy,k;

point_type point[max_n];

point_type *p=new point_type,*p_find=new point_type;

int compare(const

void* e1,const

void* e2)

inline bool is_inside(point_type* p)

void enumerate()

; if (is_inside(p))

continue;

*p=;

if (!is_inside(p))

;if (is_inside(p))

continue;

else

break;

}for (k=2;;k++)

;p_find=(point_type*) bsearch(p,point,n,sizeof(point_type),compare);

if (p_find==null)

break;

}if (!is_inside(p) && k>ans)

ans=k;

}return;

}int main()

; point_type* p=(point_type*)

bsearch

(key,point,n,sizeof(point_type),compare);

delete

key;

printf

("%d\n",p-point);

*/enumerate

(); printf

("%d\n",ans==2?0:ans);

delete

p; delete

p_find;

return 0;

}

惱人的青蛙POJ2812

解題思路 因為要求出最長的路徑,所以需要比較全部的路徑長度。對於每一條路徑,因為步長相等,所以只要確定開始兩個被踩的點就可以求出整條路徑。假設前兩個點為 x1,y1 x2,y2 則步長為dx x2 x1,dy y2 y1,需要判斷下面三個條件是否都滿足。1 之後每個點 xi,yi xi 1 dx,y...

2812 惱人的青蛙

總時間限制 2000ms 單個測試點時間限制 500ms 記憶體限制 65536kb 描述在南韓,有一種小的青蛙。每到晚上,這種青蛙會跳越稻田,從而踩踏稻子。農民在早上看到被踩踏的稻子,希望找到造成最大損害的那只青蛙經過的路徑。每只青蛙總是沿著一條直線跳越稻田,而且每次跳躍的距離都相同。如下圖所示,...

poj 1054 討厭的青蛙

這個問題看起來很複雜,其實目的很簡單 幫助農民找到為害最大的青蛙。也就是要找到 一條穿越稻田的青蛙路徑,這個路徑上被踩踏的水稻不少於其他任何青蛙路徑上被踩踏的水 稻數。當然,整個稻田中也可能根本就不存在青蛙路徑。問題的關鍵是 找到穿越稻田的全 部青蛙路徑。任何一條穿越稻田的青蛙路徑l,至少包括3 棵...