如下是我我的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]);
這麼寫就對了
可是這種錯是很難查的啊,怎麼辦呢?
其實咱們能夠在編譯時解決這個問題:
這是個好東西,它能夠在你代碼裏面找到可能的錯誤,以警告的形式提出來