前言
要講這題之前先看一下基本題,今天有N雙筷子,每一個人拿兩雙,請算出每個人所拿筷子差的平方和最小值為多少。
先將筷子從小到大排序,可以知道說對於每一雙筷子來說,與它差最小的一定是和這雙筷子相鄰的那雙。
因此假設dp(i,j)代表i個人,到第j雙筷子的最小值,可以得到
1
| dp(i,j) = min(dp(i,j-1),dp(i-1,j-2) + (l[j] - l[j-1])^2 )
|
接下來看這一題。
題意
每個人必須拿三雙筷子,但只計算較小的兩雙差的平方和,最長不計,另外不論客人多少人都要加上8個人。
解法
原本是由小排到大,所以第j雙一定是到目前為止最大的那一雙,但如此一來就不能保證還有更大的一雙可以拿,所以換個方式改成由大排到小。
因此得到下式
1
| dp(i,j) = min(dp(i,j-1),dp(i-1,j-2) + (l[j] - l[j-1])^2 ) if j >= i * 3
|
程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <iostream> #define MAXNUM 999999999 using namespace std; int dp[1001][5001] ; int chopsticks[5001] ; int main() { int number , K , N ; for ( int i = 0 ; i < 1001 ; i ++ ) dp[i][0] = MAXNUM ; for ( int i = 0 ; i < 5001 ; i ++ ) dp[0][i] = 0 ; cin >> number ; for ( int n = 0 ; n < number ; n ++ ){ cin >> K >> N ; K += 8 ; for ( int i = N ; i > 0 ; i -- ){ cin >> chopsticks[i] ; } for ( int i = 1 ; i < K + 1 ; i ++ ){ for ( int j = 1 ; j < N + 1 ; j ++ ){ if ( j < i * 3 ){ dp[i][j] = MAXNUM ; } else if ( j >= i * 3 ){ dp[i][j] = min(dp[i][j-1],dp[i-1][j-2]+(chopsticks[j]-chopsticks[j-1])*(chopsticks[j]-chopsticks[j-1])) ; } } } cout << dp[K][N] << endl ; } return 0; }
|