貪心是人類自帶的能力,貪心演算法是在貪心決策上進行統籌規劃的統稱。
比如一道常見的演算法筆試題---- 跳一跳 :
我們自然而然能產生一種解法:盡可能的往右跳,看最後是否能到達。
本文即是對這種貪心決策的介紹。
狹義的貪心演算法指的是解最優化問題的一種特殊方法,解決過程中總是做出當下最好的選擇,因為具有最優子結構的特點,局部最優解可以得到全局最優解;這種貪心演算法是動態規劃的一種特例。 能用貪心解決的問題,也可以用動態規劃解決。
而廣義的貪心指的是一種通用的貪心策略,基於當前局面而進行貪心決策。以 跳一跳 的題目為例:
我們發現的題目的核心在於 向右能到達的最遠距離 ,我們用maxRight來表示;
此時有一種貪心的策略:從第1個盒子開始向右遍歷,對於每個經過的盒子,不斷更新maxRight的值。
貪心的思考過程類似動態規劃,依舊是兩步: 大事化小 , 小事化了 。
大事化小:
一個較大的問題,通過找到與子問題的重疊,把復雜的問題劃分為多個小問題;
小事化了:
從小問題找到決策的核心,確定一種得到最優解的策略,比如跳一跳中的 向右能到達的最遠距離 ;
在證明局部的最優解是否可以推出全局最優解的時候,常會用到數學的證明方式。
如果是動態規劃:
要湊出m元,必須先湊出m-1、m-2、m-5、m-10元,我們用dp[i]表示湊出i元的最少紙幣數;
有 dp[i]=min(dp[i-1], dp[i-2], dp[i-5], dp[i-10]) + 1 ;
容易知道 dp[1]=dp[2]=dp[5]=dp[10]=1 ;
根據以上遞推方程和初始化信息,可以容易推出dp[1~m]的所有值。
似乎有些不對? 平時我們找零錢有這么復雜嗎?
從貪心演算法角度出發,當m>10且我們有10元紙幣,我們優先使用10元紙幣,然後再是5元、2元、1元紙幣。
從日常生活的經驗知道,這么做是正確的,但是為什麼?
假如我們把題目變成這樣,原來的策略還能生效嗎?
接下來我們來分析這種策略:
已知對於m元紙幣,1,2,5元紙幣使用了a,b,c張,我們有a+2b+5c=m;
假設存在一種情況,1、2、5元紙幣使用數是x,y,z張,使用了更少的5元紙幣(z<c),且紙幣張數更少(x+y+z<a+b+c),即是用更少5元紙幣得到最優解。
我們令k=5*(c-z),k元紙幣需要floor(k/2)張2元紙幣,k%2張1元紙幣;(因為如果有2張1元紙幣,可以使用1張2元紙幣來替代,故而1元紙幣只能是0張或者1張)
容易知道,減少(c-z)張5元紙幣,需要增加floor(5*(c-z)/2)張2元紙幣和(5*(c-z))%2張紙幣,而這使得x+y+z必然大於a+b+c。
由此我們知道不可能存在使用更少5元紙幣的更優解。
所以優先使用大額紙幣是一種正確的貪心選擇。
對於1、5、7元紙幣,比如說要湊出10元,如果優先使用7元紙幣,則張數是4;(1+1+1+7)
但如果只使用5元紙幣,則張數是2;(5+5)
在這種情況下,優先使用大額紙幣是不正確的貪心選擇。(但用動態規劃仍能得到最優解)
如果是動態規劃:
前i秒的完成的任務數,可以由前面1~i-1秒的任務完成數推過來。
我們用 dp[i]表示前i秒能完成的任務數 ;
在計算前i秒能完成的任務數時,對於第j個任務,我們有兩種決策:
1、不執行這個任務,那麼dp[i]沒有變化;
2、執行這個任務,那麼必須騰出來(Sj, Tj)這段時間,那麼 dp[i] = max(dp[i], dp[ S[j] ] ) + 1 ;
比如說對於任務j如果是第5秒開始第10秒結束,如果i>=10,那麼有 dp[i]=max(dp[i], dp[5] + 1); (相當於把第5秒到第i秒的時間分配給任務j)
再考慮貪心的策略,現實生活中人們是如何安排這種多任務的事情?我換一種描述方式:
我們自然而然會想到一個策略: 先把結束時間早的兼職給做了!
為什麼?
因為先做完這個結束時間早的,能留出更多的時間做其他兼職。
我們天生具備了這種優化決策的能力。
這是一道 LeetCode題目 。
這個題目不能直接用動態規劃去解,比如用dp[i]表示前i個人需要的最少糖果數。
因為(前i個人的最少糖果數)這種狀態表示會收到第i+1個人的影響,如果a[i]>a[i+1],那麼第i個人應該比第i+1個人多。
即是 這種狀態表示不具備無後效性。
如果是我們分配糖果,我們應該怎麼分配?
答案是: 從分數最低的開始。
按照分數排序,從最低開始分,每次判斷是否比左右的分數高。
假設每個人分c[i]個糖果,那麼對於第i個人有 c[i]=max(c[i-1],c[c+1])+1 ; (c[i]默認為0,如果在計算i的時候,c[i-1]為0,表示i-1的分數比i高)
但是,這樣解決的時間復雜度為 O(NLogN) ,主要瓶頸是在排序。
如果提交,會得到 Time Limit Exceeded 的提示。
我們需要對貪心的策略進行優化:
我們把左右兩種情況分開看。
如果只考慮比左邊的人分數高時,容易得到策略:
從左到右遍歷,如果a[i]>a[i-1],則有c[i]=c[i-1]+1;否則c[i]=1。
再考慮比右邊的人分數高時,此時我們要從數組的最右邊,向左開始遍歷:
如果a[i]>a[i+1], 則有c[i]=c[i+1]+1;否則c[i]不變;
這樣講過兩次遍歷,我們可以得到一個分配方案,並且時間復雜度是 O(N) 。
題目給出關鍵信息:1、兩個人過河,耗時為較長的時間;
還有隱藏的信息:2、兩個人過河後,需要有一個人把船開回去;
要保證總時間盡可能小,這里有兩個關鍵原則: 應該使得兩個人時間差盡可能小(減少浪費),同時船回去的時間也盡可能小(減少等待)。
先不考慮空船回來的情況,如果有無限多的船,那麼應該怎麼分配?
答案: 每次從剩下的人選擇耗時最長的人,再選擇與他耗時最接近的人。
再考慮只有一條船的情況,假設有A/B/C三個人,並且耗時A<B<C。
那麼最快的方案是:A+B去, A回;A+C去;總耗時是A+B+C。(因為A是最快的,讓其他人來回時間只會更長, 減少等待的原則 )
如果有A/B/C/D四個人,且耗時A<B<C<D,這時有兩種方案:
1、最快的來回送人方式,A+B去;A回;A+C去,A回;A+D去; 總耗時是B+C+D+2A (減少等待原則)
2、最快和次快一起送人方式,A+B先去,A回;C+D去,B回;A+B去;總耗時是 3B+D+A (減少浪費原則)
對比方案1、2的選擇,我們發現差別僅在A+C和2B;
為何方案1、2差別里沒有D?
因為D最終一定要過河,且耗時一定為D。
如果有A/B/C/D/E 5個人,且耗時A<B<C<D<E,這時如何抉擇?
仍是從最慢的E看。(參考我們無限多船的情況)
方案1,減少等待;先送E過去,然後接著考慮四個人的情況;
方案2,減少浪費;先送E/D過去,然後接著考慮A/B/C三個人的情況;(4人的時候的方案2)
到5個人的時候,我們已經明顯發了一個特點:問題是重復,且可以由子問題去解決。
根據5個人的情況,我們可以推出狀態轉移方程 dp[i] = min(dp[i - 1] + a[i] + a[1], dp[i - 2] + a[2] + a[1] + a[i] + a[2]);
再根據我們考慮的1、2、3、4個人的情況,我們分別可以算出dp[i]的初始化值:
dp[1] = a[1];
dp[2] = a[2];
dp[3] = a[2]+a[1]+a[3];
dp[4] = min(dp[3] + a[4] + a[1], dp[2]+a[2]+a[1]+a[4]+a[2]);
由上述的狀態轉移方程和初始化值,我們可以推出dp[n]的值。
貪心的學習過程,就是對自己的思考進行優化。
是把握已有信息,進行最優化決策。
這里還有一些收集的 貪心練習題 ,可以實踐練習。
這里 還有在線分享,歡迎報名。
2. 安卓設計規范
在講安卓設計規范之前我們先來看看一下的問題:
*規范是什麼?
*規范的目的是什麼?
*怎樣進行規范?
規范是什麼
規范:意指明文規定或約定成俗的標准。或是按照標准,規范的要求進行操作,使某一行為或某一活動達到或是超越規定的標准。
也就是說 規范通過制定一些規定與約束 (如字體大小,界面尺寸,圖標大小等) 使某一行為 (如項目開發,組件庫的組件等) 達到標准 。
制定規范的目的是 確保設計的統一性與合理性 。規范維護的是項目的統一,而不是設計師個人的設計。想一想在公司里,除了設計,前有產品經理,後有程序員,還有用戶,你做的東西都是要交給他們的。產品經理看你的設計是否展現了她的需求(設計內容是否包括前期討論的內容),程序員問你要各種切圖(圖標、組件、布局、間距、字體大小等),用戶看你的設計(顏色,圖標使用的大小范圍等),如果設計師完全沒有規范,全憑自己的「天馬行空」設計出來的東西,是會帶來很大的麻煩的,舉個簡單的例子,切圖規范,如果你的命名只有自己能看懂,那你就不要發給程序員了吧~因為發給他他也找不到哪個是哪個,這個圖標應該放在哪裡。你所做的設計是為了公司項目服務的,是為了客戶服務的,所以你設計的東西就得滿足項目中其他職位(產品經理、程序員)使用的需求,以及符合用戶的使用習慣。所以 規范是為了項目利益最大化,高效化而在團隊中制定成的約定。
不同的規范雖然內容不同但是包含的內容其實是差不多的,通常包括布局,顏色,圖標,組件,字體這幾個方面。接下來我們就來看看安卓中常見的設計規范,相信學習了之後,以後項目里的設計規范你都很清楚了,在設計中多加註意就行。一個產品設計完成之後,進行設計規范製作也是對項目總結的一個方法。能注意規范且會制定規范。
在進行app設計的時候,我們都會先建畫布大小,當然是根據安卓界面尺寸來建立的。安卓手機那麼多,不必每一個都記住。只要記住一兩個,懂得之間的換算關系就行了。
目前安卓端主流尺寸主要是@1.5x,@2x以及@3x,記住下面三個就夠用了。
@1.5x 480x854 /540x960
@2x 720x1280( 這是我最常用的界面尺寸)
@3x 1080x1920
考考你,那@1x是多少呢?
除了知道界面尺寸外,還得知道狀態欄,導航欄,菜單欄的高度是多少,設計時建立好相應的參考線。
建議取用 720 ×1280 這個尺寸,這個尺寸 720×1280中顯示完美,切圖後的圖片文件大小也適中,應用的內存消耗也不會過高。
對於圖標其實在規范上面有很多要注意的,比如圖標大小,圖標設計,圖標切圖規范,這里就重點講圖標大小,之後會再講圖標設計規范。
安卓系統中,中文使用的是谷歌思源,英文使用的是Roboto。思源字體,是一種非襯線字體,Adobe稱思源體為Source Han Sans,Google稱思源體為Noto Sans CJK. 思源體包含7個自重,也就是7中不同粗細的字體。
對於字體或許在設計過程中你會選用其他字體,但是需要注意你所用的字體是否利於用戶閱讀,是否舒服等問題。
對於字體的大小,在界面設計過程中,需要統一,比如所有正文是統一大小,所有標題是統一大小。
不同風格的字體大小,給人的感覺也是不同的,我們要學會靈活應用。安卓文字單位是sp,以下文字是按照@1x倍率來規范的
在安卓中,標注距離一般用dp,標注文字用sp,而知之間的換算關系為:
1dp=(屏幕ppi/160)px
不清楚單位的,可以去找上一篇文章了解px pt sp dp ppi。
android開發需要的設計交付物至少要有:高保真UI圖,標注,切圖
這是最後,也是最重要的一點,因為你所切的圖是要交到程序員的手裡的,他寫的程序達不到你想要的效果可能就是他看不懂你給他的規范~
1.切圖尺寸必須為雙數
2.單像素的圖會出現邊緣模糊的情況
3.命名需要規范
基本上 App 的切圖可分為下面幾大類: 背景、按鈕、圖示、圖片、照片、TabBar icon 等。
一般命名規范可以為:
前綴:位置 組件 用途
後綴:狀態
如用btn-xxx.png 來命名 。App 里的按鈕擁有 4 種屬性,分別為一般normal、點擊highlight、不能點擊disabled、選中(selected)。
但不追求精緻與完整度的話,只出一般屬性按鈕圖檔就可以了。如果是點擊(hightlight)狀態就可以命名為:btn- cancel-hightlight.png 表示取消按鈕點擊時圖標。
就算不是按照很嚴格的規范來命名,至少能讓程序員知道你這個圖標是在那種情況下使用的圖標,這就需要設計師跟程序員很好的溝通,方便整個團隊的開發,提高團隊的開發效率
3. Android 關於"尺寸"的那些事(dp,dip,sp,pt,px...)
屏幕大小:屏幕大小是手機對角線的物理尺寸,以英寸inch為單位。比如我的Mix 2手機屏幕大小為5.99 inches,意味著我的屏幕對角線長度為5.99inches = 5.99 * 2.54 = 15.2146cm
解析度:屏幕的像素點數,一般表示為a*b。例如某手機解析度為21601080,意味著手機屏幕的豎直方向(長)有2160個像素點,水平方向(寬)有1080個像素點。
px :Pixels ,像素;對應屏幕上的實際像素,是畫面中最小的點(單位色塊),像素大小沒有固定長度值,不同設備上1個單位像素色塊大小不同。
這么說可能有點陌生,用屏幕解析度來說,今年流行起來的「全面屏」解析度是 2160*1080,但是你也可以發現,雖然很多全面屏手機解析度一樣,但是明顯看得出來屏幕大小不一樣,這也解釋了「不同設備像素色塊大小是不同的」。
pt :1pt=1/72 inch,用於印刷業,非常簡單易用;
dpi :Dots Per Inch,每英寸點數;詳見ppi
ppi :Pixels Per Inch,每英寸像素數;數值越大顯示越細膩。計算式:ppi = 屏幕對角線像素數 / 屏幕對角線長度。
還是舉全面屏的例子,解析度2160*1080,屏幕大小是5.9inches,勾股定理可以得到對角線像素數大約是2415,那麼ppi = 2415 / 5.99 = 403.
事實上dpi 和 ppi 一定程度上可以劃等號,都表示像素密度,計算方式完全一致,只不過使用場景不一樣。dpi中的dots點屬於列印或印刷等領域,例如drawable 文件對應的就是dpi,而ppi中的pixel屬於屏幕顯示等領域
dp/dip : Density-independent Pixels,密度無關像素 - 基於屏幕物理密度的抽象單位。1dp等於 160 dpi 屏幕上的dpx,這是 系統為「中」密度屏幕假設的基線密度。在運行時,系統 根據使用中屏幕的實際密度按需要以透明方式處理 dp 單位的任何縮放 。dp 單位轉換為屏幕像素很簡單:px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等於 1.5 物理像素。在定義應用的 UI 時應始終使用 dp 單位 ,以確保在不同密度的屏幕上正常顯示 UI。
如果看完文章還是覺得很懵,那麼可以直接記住: 1dp單位在設備屏幕上總是等於1/160 inch。
sp :Scale-independent Pixels ,與 dp 單位相似,也會根據用戶的字體大小偏好進行縮放。
首先我們放上源碼中對尺寸單位的轉換
可以看到,輸入值類型為dp時,返回 value * DisplayMetrics.density,到這里我們可能會發懵:嗯?不對啊,前面我們不是通過px 和 dp 的換算公式來計算的么,怎麼這里就簡簡單單乘了一個DisplayMetrics.density?不要慌,我們先看看源碼中對DisplayMetrics.density的介紹。
源碼注釋中說到「在160dpi的屏幕下,density的值為1,而在120dpi的屏幕下,density的值為0.75」,我們可以大膽的猜測一下,120dpi下的density=0.75的原因是120dpi * 1 /160dpi=0.75。實際上,也就是這么回事。我們下面會仔細的分析。
需要補充一下,通常意義上Android 屏幕的密度,指的是像素密度dpi/ppi,對應於源碼中的DisplayMetrics.densityDpi。
為什麼引入dp?
Android 引入了dp這一單位,使得不論多大屏幕,多大dpi,顯示的效果始終保持一致。
但是根據前面我們提到的px與dp的換算公式px = dp * (dpi / 160),很顯然,由於相同解析度但不同屏幕大小的設備dpi是不同的,導致px和dp的基本不存在一個固定的換算關系,為了方便屏幕適配,Android設置了6個通用的密度,換算px與dp時採取通用密度計算,而非設備實際的密度。
以下為6種通用密度,以及其最小的解析度
得到上面通用密度之後,我們換算dp與px多了一種簡便方式。前面我們提到Android將mdpi作為基準,此時1px = 1dp,又有px = dp * (dpi / 160),所以我們可以很容易的得到以下換算:
還記不記得前面源碼中的density屬性,實際上DisplayMetrics.density = dpi / 160 ,表示的就是在某個通用密度下dp與px的換算比(1dp/1px的值)
這部分其實和程序員自身已經關系不大了,畢竟參與工作之後這些都是UI人員的活兒了。不過鑒於現在我還只是一枚在校生,還是記下來以免自己遺漏吧。
建議在xhdpi中作圖
原因嘛,首先現在主流解析度是1080p,以及最近流行起來的全面屏18:9,而xhdpi對應720p,向低dpi兼容自然沒問題,即便在xxhdpi中顯示,也會有個不錯的效果。而如果以1920*1080作圖,顯然圖片素材佔用的內存很大,而且也會增大應用安裝包的大小。
只有一個原則:資源放入對應dpi的文件夾中,Android會機智的載入合適的資源。
以drawable資源為例:
我們平時開發小項目&對UI要求不高時,只使用一套xhdpi的資源就足夠了,雖然這可能會導致在hdpi及以下的手機中有些卡頓,因為xhdpi的圖片運行在hdpi及以下的手機上會比較吃內存,不過無傷大雅。
而如果不為圖片資源犯愁時(有UI人員的支持,就是任性),就可以添加所有dpi的資源。當然,重點還是要滿足ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的規律。
好像說了不少廢話,哈哈,大概就這么多吧。
4. dp的定義原理和dpi,ppi,px,pt,sp之間的區別
dp = dip : device independent pixels(設備獨立像素). 不同設備有不同的顯示效果,這個和設備硬體有關,一般我們為了支持WVGA、HVGA和QVGA 推薦使用這個,不依賴像素。
px: pixels(像素). 不同設備顯示效果相同,一般我們HVGA代表320x480像素,這個用的比較多。
pt: point,是一個標準的長度單位,1pt=1/72英寸,用於印刷業,非常簡單易用;
sp: scaled pixels(放大像素). 主要用於字體顯示best for textsize。
由此,根據 google 的建議,TextView 的字型大小最好使用 sp 做單位,而且查看
TextView
的源碼可知 Android 默認使用 sp 作為字型大小單位。
在 Android 中, 1pt 大概等於 2.22sp
以上供參考,如果 UI 能夠以 sp 為單位提供設計是最好的,如果設計中沒有 sp
的概念,則開發人員也可以通過適當的換算取近似值。
過去,程序員通常以像素為單位設計計算機用戶界面。例如,定義一個寬度為300像素的表單欄位,列之間的間距為5個像素,圖標大小為16×16像素 等。這樣處理的問題在於,如果在一個每英寸點數(dpi)更高的新顯示器上運行該程序,則用戶界面會顯得很小。在有些情況下,用戶界面可能會小到難以看清 內容。
與解析度無關的度量單位可以解決這一問題。Android支持下列所有單位。
px(像素):屏幕上的點。
in(英寸):長度單位。
mm(毫米):長度單位。
pt(磅):1/72英寸。
dp(與密度無關的像素):一種基於屏幕密度的抽象單位。在每英寸160點的顯示器上,1dp = 1px。
dip:與dp相同,多用於android/ophone示例中。
sp(與刻度無關的像素):與dp類似,但是可以根據用戶的字體大小首選項進行縮放。
為了使用戶界面能夠在現在和將來的顯示器類型上正常顯示,建議大家始終使用sp作為文字大小的單位,將dip作為其他元素的單位。當然,也可以考慮使用矢量圖形,而不是用點陣圖
5. 程序員必須掌握哪些演算法
一.基本演算法:
枚舉. (poj1753,poj2965)
貪心(poj1328,poj2109,poj2586)
遞歸和分治法.
遞推.
構造法.(poj3295)
模擬法.(poj1068,poj2632,poj1573,poj2993,poj2996)
二.圖演算法:
圖的深度優先遍歷和廣度優先遍歷.
最短路徑演算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
(poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
最小生成樹演算法(prim,kruskal)
(poj1789,poj2485,poj1258,poj3026)
拓撲排序 (poj1094)
二分圖的最大匹配 (匈牙利演算法) (poj3041,poj3020)
最大流的增廣路演算法(KM演算法). (poj1459,poj3436)
三.數據結構.
串 (poj1035,poj3080,poj1936)
排序(快排、歸並排(與逆序數有關)、堆排) (poj2388,poj2299)
簡單並查集的應用.
哈希表和二分查找等高效查找法(數的Hash,串的Hash)
(poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
哈夫曼樹(poj3253)
堆
trie樹(靜態建樹、動態建樹) (poj2513)
四.簡單搜索
深度優先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
廣度優先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
簡單搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
五.動態規劃
背包問題. (poj1837,poj1276)
型如下表的簡單DP(可參考lrj的書 page149):
E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最長公共子序列) (poj3176,poj1080,poj1159)
C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最優二分檢索樹問題)
六.數學
組合數學:
1.加法原理和乘法原理.
2.排列組合.
3.遞推關系.
(POJ3252,poj1850,poj1019,poj1942)
數論.
1.素數與整除問題
2.進制位.
3.同餘模運算.
(poj2635, poj3292,poj1845,poj2115)
計算方法.
1.二分法求解單調函數相關知識.(poj3273,poj3258,poj1905,poj3122)
七.計算幾何學.
幾何公式.
叉積和點積的運用(如線段相交的判定,點到線段的距離等). (poj2031,poj1039)
多邊型的簡單演算法(求面積)和相關判定(點在多邊型內,多邊型是否相交)
(poj1408,poj1584)
凸包. (poj2187,poj1113)
中級(校賽壓軸及省賽中等難度):
一.基本演算法:
C++的標准模版庫的應用. (poj3096,poj3007)
較為復雜的模擬題的訓練(poj3393,poj1472,poj3371,poj1027,poj2706)
二.圖演算法:
差分約束系統的建立和求解. (poj1201,poj2983)
最小費用最大流(poj2516,poj2516,poj2195)
雙連通分量(poj2942)
強連通分支及其縮點.(poj2186)
圖的割邊和割點(poj3352)
最小割模型、網路流規約(poj3308)
三.數據結構.
線段樹. (poj2528,poj2828,poj2777,poj2886,poj2750)
靜態二叉檢索樹. (poj2482,poj2352)
樹狀樹組(poj1195,poj3321)
RMQ. (poj3264,poj3368)
並查集的高級應用. (poj1703,2492)
KMP演算法. (poj1961,poj2406)
四.搜索
最優化剪枝和可行性剪枝
搜索的技巧和優化 (poj3411,poj1724)
記憶化搜索(poj3373,poj1691)
五.動態規劃
較為復雜的動態規劃(如動態規劃解特別的旅行商TSP問題等)
(poj1191,poj1054,poj3280,poj2029,poj2948,poj1925,poj3034)
記錄狀態的動態規劃. (POJ3254,poj2411,poj1185)
樹型動態規劃(poj2057,poj1947,poj2486,poj3140)
六.數學
組合數學:
1.容斥原理.
2.抽屜原理.
3.置換群與Polya定理(poj1286,poj2409,poj3270,poj1026).
4.遞推關系和母函數.
數學.
1.高斯消元法(poj2947,poj1487, poj2065,poj1166,poj1222)
2.概率問題. (poj3071,poj3440)
3.GCD、擴展的歐幾里德(中國剩餘定理) (poj3101)
計算方法.
1.0/1分數規劃. (poj2976)
2.三分法求解單峰(單谷)的極值.
3.矩陣法(poj3150,poj3422,poj3070)
4.迭代逼近(poj3301)
隨機化演算法(poj3318,poj2454)
雜題(poj1870,poj3296,poj3286,poj1095)
七.計算幾何學.
坐標離散化.
掃描線演算法(例如求矩形的面積和周長並,常和線段樹或堆一起使用)
(poj1765,poj1177,poj1151,poj3277,poj2280,poj3004)
多邊形的內核(半平面交)(poj3130,poj3335)
幾何工具的綜合應用.(poj1819,poj1066,poj2043,poj3227,poj2165,poj3429)
高級(regional中等難度):
一.基本演算法要求:
代碼快速寫成,精簡但不失風格
(poj2525,poj1684,poj1421,poj1048,poj2050,poj3306)
保證正確性和高效性. poj3434
二.圖演算法:
度限制最小生成樹和第K最短路. (poj1639)
最短路,最小生成樹,二分圖,最大流問題的相關理論(主要是模型建立和求解)
(poj3155, poj2112,poj1966,poj3281,poj1087,poj2289,poj3216,poj2446
最優比率生成樹. (poj2728)
最小樹形圖(poj3164)
次小生成樹.
無向圖、有向圖的最小環
三.數據結構.
trie圖的建立和應用. (poj2778)
LCA和RMQ問題(LCA(最近公共祖先問題) 有離線演算法(並查集+dfs) 和 在線演算法(RMQ+dfs)).(poj1330)
雙端隊列和它的應用(維護一個單調的隊列,常常在動態規劃中起到優化狀態轉移的目的). (poj2823)
左偏樹(可合並堆).
後綴樹(非常有用的數據結構,也是賽區考題的熱點).(poj3415,poj3294)
四.搜索
較麻煩的搜索題目訓練(poj1069,poj3322,poj1475,poj1924,poj2049,poj3426)
廣搜的狀態優化:利用M進制數存儲狀態、轉化為串用hash表判重、按位壓縮存儲狀態、雙向廣搜、A*演算法. (poj1768,poj1184,poj1872,poj1324,poj2046,poj1482)
深搜的優化:盡量用位運算、一定要加剪枝、函數參數盡可能少、層數不易過大、可以考慮雙向搜索或者是輪換搜索、IDA*演算法. (poj3131,poj2870,poj2286)
五.動態規劃
需要用數據結構優化的動態規劃.(poj2754,poj3378,poj3017)
四邊形不等式理論.
較難的狀態DP(poj3133)
六.數學
組合數學.
1.MoBius反演(poj2888,poj2154)
2.偏序關系理論.
博奕論.
1.極大極小過程(poj3317,poj1085)
2.Nim問題.
七.計算幾何學.
半平面求交(poj3384,poj2540)
可視圖的建立(poj2966)
點集最小圓覆蓋.
對踵點(poj2079)
6. 程序員如何選電腦
在商用辦公領域,有這樣跟一群人十分特殊,每天面對密密麻麻的編程代碼,他們就是程序員。程序員們對電腦的性能要求較高,不僅需要處理復雜的運算和變成,更需要勝任多任務處理,一台性能出色的台式電腦是比較好的選擇,能夠保障復雜工作的穩定完成。那麼程序員該如何選配電腦呢?
首先整潔的辦公環境能夠提高程序員的編程效率。試想,原本就已經十分擁擠的辦公桌,如果在桌面堆上一個大型機箱,顯然看著就很煩人,可是如果將機箱放置在桌下,使用介面就顯得不那麼方便了。因此,一個小巧、迷你的台式電腦可以很好解決這個問題,既滿足了介面轉接的易用性又不影響桌面的整潔程度與空間利用。惠普EliteDesk 800 G2 DM就是一款可以滿足程序員開發需求的商用迷你PC。
整潔的辦公環境能夠提高程序員的編程效率
惠普EliteDesk 800 G2 DM造型相對保守,但是卻不給人呆板的感覺。長方體的造型左右側邊完全平坦,惠普EliteDesk 800 G2 DM可以很容易地在桌面平台上豎直擺放,大大節省用戶的空間佔用。另外,市售產品還搭配有附贈的支撐底座,增強立式擺放的穩定性。
惠普EliteDesk 800 G2 DM可以很容易地在桌面平台上豎直擺放,大大節省用戶的空間佔用
惠普EliteDesk 800 G2 DM整機是一個標準的矮個子長方體,厚度不大,俯仰截面接近正方形,長寬比較小,不像書本更像是過去的一些小型收音機。整機材質採取鋼制外殼,手指彈上去清脆作響,強度不是問題,十分結實,只有前面板採取了塑料材質,其前面板散熱孔設計頗有一種舊時的情懷。
整機材質採取鋼制外殼不像書本更像是過去的一些小型收音機
其次擴展性一定要強,程序員在工作時還需要轉接各類基於USB口或者其他介面的設備。而作為一款商用迷你機設備,外部擴展能力也是十分重要的,迷你機身設計並沒有給惠普EliteDesk 800 G2 DM的介面配置帶來影響。
惠普EliteDesk 800 G2 DM的介面配置
惠普EliteDesk 800 G2 DM配備了2個USB2.0、8個USB3.0介面、耳機/麥克風介面、2個DP介面、VGA介面以及RJ45網線介面;十個USB介面可以充分滿足程序員的多設備調試需求,三個視頻輸出介面可以輕松轉接多個顯示屏,無疑是提高工作效率的有效手段。
惠普EliteDesk 800 G2 DM的前面板和上表面為整體可拆卸式外殼設計
另外,惠普EliteDesk 800 G2 DM的前面板和上表面為整體可拆卸式外殼設計,只用一顆螺絲在後方負責固定,拆解起來較為簡便。由前面板和上表面連接而成的頂蓋,只需輕輕滑動即可抽離,內部一覽無余,值得一提的是,後方固定用的螺絲並不能完全擰下,是惠普為了防止用戶弄丟螺絲做的設計。
既然是程序開發的硬體需求,足夠強勁的性能表現是最為重要的,這直接影響到多任務處理的效率。以惠普EliteDesk 800 G2 DM為例,該機配備了英特爾第六代酷睿i7-6700四核vPRO處理器並且搭配DDR4 2133MHz內存。酷睿i7-6700採用四核設計、8MB三級緩存、3.4GHz主頻支持睿頻至4.0GHz、工作功率65W,這顆處理器不僅能提供強勁的性能輸出,並且還能有良好的穩定性,vPRO技術還能擴展不少企業功能。
配備英特爾第六代酷睿i7-6700四核vPRO處理器
程序設計過程中需要大量的編程運算,酷睿i7-6700可以提供長時間穩定且高效的高性能輸出。處理器性能方面我們採用三款同系列測試軟體CINEBENCH對其性能測試,得出的結果僅供參考。首先是CINEBENCH R10的測試結果,該處理器獲得單核7928分,多核31362分;在CINEBENCH R11.5測試中,該處理器多核心獲得8.87pts,單核心1.92pts;最後在CINEBENCH R15測試中,該處理器多核心獲得802cb,單核心169cb。處理器單項測試結果表明該處理器定位於桌面平台處理器高端型號。
CINEBENCH R10的測試結果
CINEBENCH R11.5的測試結果
CINEBENCH R15的測試結果
除此之外,惠普EliteDesk 800 G2 DM搭載的第六代酷睿支持DDR4 2133MHz內存,相對過去的DDR3內存在頻率上有著十足的提升,頻率更高意味著高負荷處理一些文件時能有更好的性能輸出,可以進一步提升運算效率。另外,配備SSD固態硬碟更是為響應速度加足了馬力,近年來機械硬碟普遍拖累了整機性能表現,而SSD固態硬碟擁有高速的讀寫速度,高性能酷睿處理器搭配高速率SSD可以滿足中高強度的開發需求。
7. DPI和PPI
不論是DPI還是PPI,實際都是一種換算的概念,即將圖片承載的信息換算為現實中的圖片(即人眼能實際看到的圖像)。DPI和PPI的區別在於換算的途徑不同,DPI面向的是印刷受體,而PPI面向的是熒幕。
PPI是英文Pixels Per Inch的縮寫,意為像素每英寸。英寸是常用的長度單位,大約相當於2.54厘米。而像素是專用於熒幕的概念,指的是熒幕可以解析的最小的點。因此,PPI值得是像素在熒幕上的密度,PPI越高圖像就越清晰
舉例來說,如果電腦屏幕是2K解析度,即1920×1080像素,它的圖像寬為1920像素。而如果這個電腦屏幕的物理寬度是19.2英寸,電腦屏幕是解析度就是1920/19.2=100PPI。
DPI是英文Dots Per Inch的縮寫,意為點每英寸。應粗你還是那個英寸,但是點的意義有很多。一般來講,你可以把Dot理解為取樣點,即物理設備可以解析的最小單位。在印刷時,它就可以作為印刷網點,而在滑鼠等電子設備上,可以理解為最小操作閾值(即設備會把多麼遠的兩個點當作一個點來處理)。
我們仍然拿1920×1080像素的圖片來舉例子,如果印刷設備的解析能力剛好是100DPI,而且你要印製的紙張尺寸剛好是19.2英寸,那麼印刷設備就可以剛好把一個像素作為一個取樣點,印刷完成後圖片的保真度是百分之百(也就是圖片所有的視覺信息都被印刷出來了)。在大多數情況下,這幾個數值都不那麼整好,因此保真度會產生損失。
1.在條件允許的情況下,圖片解析度越高越好 我們可能不會有精力去關心圖片信息量的DPI是多少,印刷設備的DPI又是多少這種細節的問題。但有一點是可以確定的,那就是圖片只要足夠大,印刷就會清晰。
2.如果有可能,使用准確的數值 許多軟體可以幫助你了解圖片實際尺寸下的PPI,比如使用Photoshop,在300PPI下創建A4的文件(尺寸21×29.7厘米,對應解析度2480×3508像素)並做出圖片,那麼大多數情況下都可以完美印刷。
正如前文所述,大多印刷設備的解析能力是300DPI,因此在該圖片的信息量下,1個像素剛好對應1個點,甚至不需要柵格處理。而如果你強行使用400PPI來創建A4尺寸的文件,拿到300DPI的設備上會被柵格,說不定還不如300DPI的質量好(畢竟是有損處理,但這種差別未必能看得出來)。
下圖是蘋果官方對iPhone 機型的介紹:
拿iPhone7 Plus來說:
屏幕尺寸:5.5英寸
手機解析度(像素):1920 (高)x 1080(寬)
PPI:401
屏幕尺寸:表示手機屏幕對角線的長度,單位是英寸。1英寸(inch)=2.54厘米(cm)
手機解析度:解析度可以從顯示解析度與圖像解析度兩個方向來分類。
顯示解析度(屏幕解析度):屏幕 圖像 的精密度,是指 顯示器 所能顯示的 像素 有多少。由於屏幕上的點、線和面都是由像素組成的,顯示器可顯示的像素越多,畫面就越 精細 ,同樣的屏幕區域內能顯示的信息也越多。
圖像解析度:單位英寸中所包含的像素點數,其定義更趨近於解析度本身的定義。
解析度的單位:(dpi 點每英寸 )、lpi(線每英寸)和ppi( 像素每英寸 )。但只有lpi是描述光學解析度的尺度的。雖然dpi和ppi也屬於解析度范疇內的單位,但是他們的含義與lpi不同。而且lpi與dpi無法換算,只能憑經驗估算。ppi和dpi經常都會出現混用現象。但是他們所用的領域也存在區別。從技術角度說,「像素」只存在於電腦顯示領域,而「點」只出現於列印或印刷領域。
ppi:Pixels Per Inch,屏幕像素密度,每英寸屏幕所擁有的像素數,在電腦顯示領域使用。
dpi:Dots Per Inch,每英寸長度上的點數,在列印領域使用。
屏幕像素密度,解析度,屏幕尺寸的關系
所以美工使用PS作圖的大小為手機解析度的大小。
如需要設計適配iPhone7的手機,我們使用1334 x 750px大小
但有一點是特殊的,就是iPhone6(s) plus、iPhone7 plus,我們需要使用2208 x 1242px大小,
原因:
ppi為326的手機,使用的為@2x的素材,對於ppi是401的手機,理論上蘋果應該用401/326 * @[email protected]的素材。但是這個奇葩的比例對開發者而言很難切圖。所以蘋果為方便開發者用的是@3x的素材,然後再縮放到@2.46x上,實際上是縮放到2.46/3=83%。實際上蘋果選取了一個接近比例的87%。
這樣算下來,物理解析度和虛擬分比率的比例是87%,也就是1920/0.87=2208,1080/0.87=1242.
好處就是開發者更方便,比如准備素材時,字型大小可以直接調成3x的。
概述
前段時間看了小米8的發布會,其中屏幕參數是如下介紹的:
當時我就在想這都是怎麼算出來的,雖然我知道 PPI 是指屏幕每一英寸上包含的像素點,但是稍微往深一想我發現我對這些參數真的很迷茫,好奇心驅使我做了些調查。
像素,英文為 Pixel ,是我們日常最熟悉不過的了,但是深入進去會發現其蘊含的知識量是巨大的,此篇對於像素話題也只是淺嘗輒止,拋磚引玉。
討論像素需要分不同的場景: 1. 數字圖像 我們程序員日常工作中接觸並討論的像素大多是指這個范疇。
光柵圖片(Bitmap)是我們日常接觸最多的,例如 jpg,jpeg,png,gif,bmp等等,另一種比較常見的就是矢量圖了。 光柵圖片是由一個一個像素組成的,那麼像素包含哪些信息?有物理尺寸嗎?
每個像素由顏色信息組成,有的還包含一個透明度信息。因為可以通過三原色 Red , Blue , Green 來混合出很多種顏色,所以一個像素就可以使用存儲這三種顏色的一個數據結構表示。一個像素佔用內存的大小,與其使用多少位來表示這些顏色有關,例如最簡單的像素只有一個 bit ,那麼它只能表示兩個狀態,0或者1,對應到圖像上也就是黑白。當一個像素達到24 bit 的時候,RGB每個通道佔8位,可以組合出來的顏色已經有1677萬色(256 256 256=16,777,216)種了,而人類眼睛可以分辨的顏色也只有大概1000多萬種,此時就是真彩色了。當然還有32位真彩色,感興趣的可以去研究。
圖片來自 維基網路
那麼通過以上的介紹,我們可以得出結論,此處的像素沒有物理尺寸,僅僅是一些數據,只有將其顯示在物理設備上才會存在物理尺寸。
可以通過下圖感受一下
圖片來源
討論解析度仍然需要分討論場景 1. 數字圖像 此時解析度是用來描述圖片的像素信息的,比如我們說一張圖片的解析度是1280 720,那麼僅僅是說明這張圖片是由1280個像素 720個像素組成的。如下圖所示,至於這張圖片的尺寸有多大,清晰還是模糊,這取決於它自身的存儲格式以及用來顯示它的設備。
2. 硬體顯示設備 是指這塊屏幕所包含的像素(這個像素是物理上的,前面我們已經討論過了)。例如小米8的屏幕解析度為2248x1080,說明這塊屏幕包含了這么多物理像素。
那麼圖片的解析度與屏幕的分別率是什麼關系呢?這需要清楚了 PPI 後才可以回答這個問題。
DPI 是印刷業使用的單位,其表示的是列印紙上每一英寸包含的墨點數量,而 PPI 是電子屏幕上每一英寸上包含的可定址物理物理顯示單元。其中英寸是西方慣用長度單位,等於2.54厘米。這兩個概念之所以如此容易混淆,就是因為一些軟體提供商做的孽,例如Microsoft,Adobe,Apple 等等,他們經常將這兩個概念互換使用。
PPI : Pixels Per Inch, 每一英寸上包含的像素個數。 這個值越高,屏幕的顯示能力越強,例如小米8 PPI的計算方式如下圖所示
可見小米8的 PPI 是401.6,而其官方宣稱為402,估計是四捨五入了,不過不知道半個像素怎麼處理,知道的可以告訴我一下。
DPI : Dots Per Inch, 每一英寸上包含的點個數。 與PPI計算方式一樣,只是應用的領域不同,這個用在印刷業的。
至此我們可以回答圖片的解析度與屏幕的解析度的關系了,以小米8為例,按照 圖片比例全屏 顯示某一張圖片: 第一:當將一張1080 2248像素的圖片顯示在Mi8上時,屏幕上的每一個物理像素對應一個圖片像素,可以完美顯示。 第二:當將一張2000 2248像素的圖片顯示在Mi8上時,Mi8的屏幕在寬度上是無法顯示的,所以顯卡會將圖片光柵化,通過一定的演算法將2000個像素減少到1080個像素,由於是從多到少的處理,所以圖片是清晰的。 第三:當將一張720*1280像素的圖片顯示在Mi8上時,顯卡會將圖片光柵化,將圖片以其中一邊為標准拉伸,圖片會變模糊。
Pt :漢語翻譯為 榜 ,是一個物理尺寸,長度為1/72 英寸,在概念上Pt與Px毛關系也沒有,但是在 photoshop 中就有關系了。 photoshop 中的pt卻是一個相對單位(這幫二貨各種混用)
換算公式: 1pt= (DPI / 72) px 。
dp : Density-independent Pixels, 這個是Android基於物理設備的 ppi 抽象出來的一個單位。它是以 160dpi 的屏幕為基準定義的,在 160dpi 的屏幕的屏幕上 1dp=1px ,那麼我們就可以得出其
換算公式: 1dp=(屏幕ppi/ 160)px
目前Android系統的屏幕分類如下表 |密度分類| 屏幕密度 | |--|--| |ldpi |120dpi | |mdpi |160dpi | |hdpi |240dpi | |xhdpi |320dpi | |xxhdpi |480dpi | |xxxhdpi |640dpi |
sp : Scale-independent Pixels,其與dp基本一樣,也是像素無關的,但是是用在描述字體的大小上。其尺寸會同時相應屏幕密度以及用戶對字體的偏好設置。 例如:在手機的字體設置為默認大小時,使用 dp 與 sp 描述字體的大小是一樣的,如下圖
但是當我們改變了手機的字體默認設置的字型大小後, dp 描述的字體大小沒有變化,但是 sp 描述的字體大小卻相應的發生了變化,如下圖。
除此之外 dp 與 sp 再無差異,一般建議字體使用 sp 作為單位。
dip 就是 dp 互為別名,沒有任何區別,其與 px 關系見上文。
以上就是關於顯示接觸GUI開發的程序員應該了解的,本來以為很簡單,但是調查後發現再往深研究我將會陷入泥潭無法自拔。同時我也感受到,人類社會發展到目前的水平,任何一個門類的知識都足以讓一個人投入終身的時間去研究,那我們程序員除了賺錢養家是不是應該找個自己感興趣方向忠貞不渝的投入一生業余精力去嘗試研究一番呢?在此我覺得我很挫敗,突然發現自己這么大年紀了竟然沒有愛好,如果愛好美女這個不算的話。。。!
我們的原圖是一份長寬都是1800像素的圖片。
這張圖片長寬都是1800像素 ,對它自己而言,DPI和PPI沒有意義。
它的解析度參數,僅僅是1800像素而已。
假設我們的所有印刷機、列印機、噴繪機,在原尺寸下都將1像素映射為1個點(即1Px/Dots),可以進行下面這些計算。
如果我們使用300DPI的印刷機,原尺寸列印這張圖,那麼它的長寬為:
1800 Px / (1Px/Dots) / 300 DPI = 6 in 即長寬都是6英寸(15.24厘米)。
如果我們使用220DPI的列印機, 原尺寸列印這張圖,那麼它的長寬為:
1800 Px / (1Px/Dots) / 220 DPI ≈ 8.19 in 即長寬都是8.19英寸(20.8厘米)。
如果我們使用72DPI的噴繪機, 原尺寸列印這張圖,那麼它的長寬為:
1800 Px / (1Px/Dots) / 72 DPI = 25 in 即長寬都是25英寸(63.5厘米)。
使用81PPI的一般顯示器,原尺寸顯示這張圖, 那麼它的長寬為:
1800 Px / 81 PPI ≈ 22.2 in 即長寬都是22.2英寸(56.4厘米)。
顯示器的PPI 我們假設顯示器是方形像素,那麼顯示器的PPI是由它的解析度和長寬共同決定的。
即顯示器的橫向PPI=顯示器的橫向解析度(Px)/顯示器的寬度(in)。
我們常說的顯示器的英寸數,是其對角線的長度。 對於16:9的顯示器來說,PPI可以這樣計算:
PPI = sqrt { (像素寬 * 像素高) / [16 * 9 * 英寸數^2 / (16^2 + 9^2)] }
舉例來說,1920*1080像素的24寸顯示器,PPI就是:
PPI = sqrt { (1920 * 1080) / [16 * 9 * 24^2 / (16^2 + 9^2)] } ≈ 91.7878
下面的表格計算了常見顯示器尺寸的PPI,你可以用這個公式檢驗: