子矩陣 解題報告

2022-07-18 05:36:10 字數 3031 閱讀 2206

目錄2. 動態規劃

3. 一半dfs一半dp

總結時間到!

在乙個n行m列的矩陣中,選出乙個r行c列的子矩陣,使相鄰元素的差的絕對值的和最小。

解題思路

在乙個n行m列的矩陣中,選出乙個 \(r\) 行 \(c\) 列的子矩陣,相當於乙個 \(n\) 行 \(m\) 列的矩陣,在 \(n\) 行中選出 \(r\) 行,在 \(m\) 列中選出 \(c\) 列,選出的行和列相交的點就是選出的數。

所以乙個很簡單的辦法,就是列舉 \(n\) 行中選哪 \(r\) 行, \(m\) 列中選哪 \(c\) 列。這就是乙個組合問題,相當於列舉 \(r \choose n\) 和 \(c \choose m\)。

這個演算法的時間複雜度,就是列舉的 \(r \choose m\)

\(\times\)

\(c \choose m\) 在乘上計算的 \(r \times c\) ,剛好可以得60分。

**大致是這樣實現的:

列舉 \(r \choose m\)

列舉 \(r \choose m\)

在第二步列舉完後求值,更新答案

列舉組合,可以用dfs來實現:

int n, r, a [ maxn + 1 ];

void solve ( int step )

for ( int i = a [ step - 1 ] + 1; i <= n; i ++ ) a [ step ] = i, solve ( step + 1 );

}

你可以拿這個**去實現一些題目(當然不行),你會發現,在 \(n<=15\) 的時候大致可以過(主要看評測機是賽揚還是i99900k),但是你可以試一試這道題,tle的很厲害。

仔細觀察i的範圍,這裡顯然可以做一些優化。

"\(i <= n\)" 這個範圍很不合理,如果剩餘空間不夠 \(r - step\) 個,肯定不可能。

因此,\(n - i\) 必須 \(>= r - step\),轉化得到 \(i <= n - r + step\)。

**只用修改一處,就是把for ( int i = a [ step - 1 ] + 1; i <= n; i ++ )變為for ( int i = a [ step - 1 ] + 1; i <= n - r + step; i ++ )

**1回到這道題目上,**實現很簡單:

//主程式請自行實現

void dfs1 ( int step )

for ( int i = row [ step - 1 ] + 1; i <= n - r + step; i ++ ) row [ step ] = i,dfs1 ( step + 1 ); }

void dfs2 ( int step )

for ( int i = col [ step - 1 ] + 1; i <= m - c + step; i ++ ) col [ step ] = i,dfs2 ( step + 1 );

}

如果用dp,可以 參考其他題目 這樣寫:

\(f [ n ] [ r ] [ m ] [ c ]\) 表示 \(n\) 列中取 \(r\) 列,\(m\) 列中取 \(c\) 列,第 \(n\) 行和第 \(m\) 列必須取時的最小分值。

但這樣寫會出現狀態不明確的問題,也就是有後效性。

不能全部用dp,那咋辦???

別急,看後面 》

解題思路

既然全部dp或者記憶化狀態會不明確,那麼通過再列舉就可以確定狀態了(這裡選擇列)。

\(f [ i ] [ j ]\) 表示 \(i\) 列中取 \(j\) 列,第 \(i\) 列必需取的最小分值

\(f [ i ] [ j ] = \min_ ^ + \sum_ ^ }\)

(\(2 \leq i \leq m, 2 \leq j \leq min ( i, c ), j - 1 \leq k < i\))

這樣寫出的dp大致是這麼一坨東西:

/*

請先預處理:

col [ i ] 表示i列內部的分值(相當於第乙個sigma)

cc [ i ] [ j ] 表示第i列與第j列相鄰時,他們列之間相差的分值(相當於第二個sigma)*/

for ( int i = 2; i <= m; i ++ )

for ( int j = 2; j <= min ( i, c ); j ++ )

for ( int k = j - 1; k < i; k ++ )

f [ i ] [ j ] = min ( f [ i ] [ j ], f [ k ] [ j - 1 ] + col [ i ] + cc [ k ] [ i ] );

再結合一下之前的dfs,寫出**:

**2

//同樣,主程式請自行實現

//碼風小清新,多多照顧

//適當做了一些優化(630ms)

void dfs ( int x )

}} for ( int i = 1; i <= m; i ++ )

}for ( int i = 1; i <= m; i ++ )

for ( int i = 2; i <= m; i ++ )

}} for ( int i = c; i <= m; i ++ )

return;

} for ( int i = row [ x - 1 ] + 1; i <= n - r + x; i ++ )

}

誒,這道題主要是乙個dfs和dp結合的玩意。

當發現dfs轉dp會產生後效性時,有兩種方法:

加狀態再搜尋

第一種方法顯然不現實 十六維陣列,為啥不給把16g記憶體全用上呢?(手滑=手動滑稽

那就只能用第二種方法,就產生了這一坨dfs+dp的東東。

解這種煩人的村民題時,一般先打乙個暴力(noip2014,如果前三題ac,一等獎穩穩的),再去優化成dp or 記憶化。

哎嗎,這篇題解寫了我好幾年喲,贊乙個唄

數論之矩陣解題報告2

hdu 2256 不得不感嘆一下,牛 x的題,牛 x的解法,開頭做的時候直接用 double 二分冪求解,但是很不幸測試樣例都沒有過,估計是精度不夠,到 n 5的時候就差了好多,但是如果把這個答案分成兩個部分分別用整數表示呢?那就能很好的解決了精度的問題,本題就很巧妙的運用了共軛數 hdu 1568...

BZOJ 3288 Mato矩陣 解題報告

這個題好神呀。orz taorunz 有乙個結論,這個結論感覺很優美 ans prod varphi i 至於為什麼呢,大概是這樣子的 對於每個數字 x 第 x 行有 x varphi x 個數字不為 1 則說明這一行要被消 x varphi x 次 別忘了每一行都會被 1 給消一次 每次消元都會令...

解題報告 NOIP2015 子串

這是一道dp題,然後來想想怎麼表示狀態,對答案有影響的就是a串的第i個字元,b串的第j個字元,和k個子串,簡單來說就是和選取的字元和子串的數量有關.那麼設 f i j kk 表示在a串的前i個字元中選kk個子串匹配b串的前j個字元的方案數.求方案數可以採用加法原理,考慮a串的第i個字元,那麼這個字元...