OI中坑點總結

如下是我我的OI生涯中遇到的坑點的一個小總結,多是我太菜了,老是掉坑裏,請大佬勿噴

1,多重揹包的轉移的循環順序數組

 

//默認每一個物品體積爲一(不想打碼……) //dp[i]表示佔用揹包容量i所能得到的最大價值
for(int i=1;i<=n;i++) for(int j=sum;j>0;j--)        //sum表示揹包最大容量
        for(int k=0;k<=num;k++)    //num表示這個物品的數量,k表示選取當前物品k件
            if(j>=k) dp[j]=min(dp[j],dp[j-k]+value);

簡單的多重揹包模板,對於學過的人,大概清晰易懂吧spa

 

//dp[i]表示佔用揹包容量i所能得到的最大價值
for(int i=1;i<=n;i++) for(int k=0;k<=num;k++)    //num表示這個物品的數量,k表示選取當前物品k件
        for(int j=sum;j>k;j--)        //sum表示揹包最大容量
            dp[j]=min(dp[j],dp[j-k]+value);

很類似的代碼,只是改了循環順序,可是爲何會錯呢?

類比01揹包的倒序轉移,

考慮對於某種物品,標程中先枚舉 j ,再枚舉 k ,這樣對於每一個位置 j ,只能先於位置 j - i ,由 j - i ( i ∈ [ 0 , k ] )轉移一次

而錯誤寫法中,對於位置 j ,能夠由轉移過的位置 j - i 轉移而來

這爲何會致使錯誤呢?考慮在 j 以前, j - i 已經由 j - i1 - i2 轉移而來,多重揹包的物品是能夠組合的,因此以上的轉移等價於 dp[ j - i1 - i2 ] 直接轉移到 dp[ i ] ,而咱們不能保證 i1 + i2 <= num ,便可能會取多於物品總數的物品

舉個例子:

物品數量爲7,咱們枚舉位置13,由8轉移而來,而在此以前,位置8由4轉移而來,等價於位置13由位置4轉移而來,13-4=9>7,轉移非法調試

2,對拍fc玄學錯誤

由於樣例廣泛太水,對拍就成爲了信息學競賽中的經典調試手段

其中對比標準答案與你的程序的答案時,經常使用到fc,就是文件比較

考場上建議寫對拍程序用system來回跑直到出錯,再把錯誤數據拎出來用cmd跑,由於cmd會告訴你全部不同的地方

code

 



可是有時候會遇到這樣的問題:

人眼看都同樣,文件比較就是不同

在懷疑程序寫崩開始亂改以前,不如看看是否是遇到了下面幾種狀況

(1)先看看這個
blog

 



這是換行符的問題,你的程序可能比標程的答案差幾個換行符,很少解釋,考慮到這種問題的可能就好

(2)還有這個



這個甚至拿出來看都同樣,有心人還會發現錯誤總在輸出結尾,可是看到程序結尾如出一轍,其實這是行末空格的問題(╯°Д°)╯︵┻━┻……
get

 

3,矩陣壓縮重複

矩陣壓縮???好啦,其實我也不知道叫什麼了,因此給它起了這個名字(*/ω\*)

大意就是,若是給你一個矩陣n<=50000,m<=50000,開數組顯然是開不下的,若是再給一個條件n*m<=500000呢,普通的二維數組仍是布星,因此咱們使用vector使用一維數組

把矩陣的一個位置轉到一維數組上

我喜歡這麼轉,對於n行m列的矩陣,位於第i行第j列的元素的pos=(i-1)*m+j

這樣就把矩陣上的每一個位置轉爲1~n*m的

可是前提是你不會使用位置0,若是你使用了位置0還用這個映射

那麼你會發現,本行第一個元素和上一行的最後一個元素pos值相等(在線出鍋)

因此就要用pos=(i-1)*(m+1)+j了

同理,使用第0行就是pos=i*(m  or  m+1)+j

ps:我在這出鍋卻是沒有調過久,可是仍是由於這個WA了好幾回水題呢
cmd

 

4,樹的直徑合併

來看一個小題:給兩棵樹,咱們能夠在兩棵樹上任意兩點之間連邊,使這兩棵樹合併爲一棵新樹,求新樹的最小直徑

學過樹的直徑的同窗都知道,lennewtree=(lentree1+1)/2+(lentree2+1)/2+1

式子沒錯,可是拿不到分,爲何呢

考慮其中一棵樹的直徑遠大於另外一棵,

因此咱們知道了,完整的式子應該是這樣的

lennewtree=max(max(lentree1,lentree2),(lentree1+1)/2+(lentree2+1)/2+1)
io

 

5,開數組
編譯

 

1,離散化數組模板


2,記得樹狀數組開數組是按值域開的

這樣就必定要考慮開到極值

有這麼一種狀況,好比這個題,[SCOI2014]方伯伯的玉米田,咱們樹狀數組的第二維是按高度開的,1<=ai<=5000,可是咱們在運行過程當中有把玉米拔高這麼一種狀況,有效的值域範圍應爲ai+k<=5500

 

6,如何避免低級錯誤

啊啊啊,這個東西這麼好用,太好用了啊啊啊

dis[v=vc[i]]=min(dis[v],dis[x]+d2[i]);

 

看這行代碼

是一個普通的dfs過程,可是錯了

這個就涉及到運算優先級的問題了,由於它是從右向左算的

而後算到dis[v]的時候,v尚未賦值

v=vc[i];
dis[v]=min(dis[v],dis[x]+d2[i]);


這麼寫就對了

可是這種錯是很難查的啊,怎麼辦呢?

其實咱們能夠在編譯時解決這個問題:



這是個好東西,它能夠在你代碼裏面找到可能的錯誤,以警告的形式提出來

相關文章
相關標籤/搜索