NOIP2008 傳紙條(DP及滾動陣列優化)

2022-05-05 18:42:08 字數 2717 閱讀 8568

傳送門

這道題有好多好多種做法呀……先說一下最暴力的,o(n^4的做法)

我們相當於要找兩條從左上到右下的路,使路上的數字和最大。所以其實路徑從**開始走並不重要,我們就直接假設全部是從左上出發的好啦。設dp[i][j][p][q]表示第一條路列舉到點(i,j),第二條路列舉到點(p,q)時,當前能取到的最大值。

這樣dp方程很顯然,就是dp[i][j][p][q] = max(dp[i-1][j][p-1][q],dp[i][j-1][p-1][q],sp[i-1][j][p][q-1],dp[i][j-1][p][q-1]) + a[i][j] + a[p][q].如果i==p && j == q,那麼減去乙個a[i][j].最後dp[m][n][m][n]即為結果。

四層迴圈列舉,複雜度o(n^4),上一下**。

#include#include

#include

#include

#define rep(i,a,n) for(ll i = a;i <= n;i++)

#define per(i,n,a) for(ll i = n;i >= a;i--)

#define enter putchar('\n')

using

namespace

std;

const

int m = 105

;typedef

long

long

ll;int

read()

while(ch >= '

0' && ch <= '9'

)

return ans *op;

}int m,n,dp[55][55][55][55],a[55][55

];int

main()

printf(

"%d\n

",dp[m][n][m][n]);

return0;

}

之後我們說一下怎麼優化。兩條路在走的時候,因為每次只能向右或者下走一格,所以兩者必然是在同一條斜對角線上的(一條從右上到左下的對角線)那麼我們就可以用對角線的橫縱座標和來表示當前dp到了**,之後每次只要列舉兩個點的橫座標就可以把路徑表示出來(也就是表示出來當前列舉的是哪兩個點)。這樣的話就可以把dp過程的時空降到三維的。

具體的寫法也很簡單,直接看一下**即可。

#include#include

#include

#include

#include

#include

#define rep(i,a,n) for(int i = a;i <= n;i++)

#define per(i,n,a) for(int i = n;i >= a;i--)

#define enter putchar('\n')

using

namespace

std;

typedef

long

long

ll;const

int m = 60

;int n,m,f[m][m],dp[120

][m][m],q[m];

intread()

while(ch >='

0' && ch <= '9'

)

return ans *op;

}int

main()}}

printf(

"%d\n

",dp[n+m][m][m]);

return0;

}

之後,時間複雜度基本已經不能再優化,不過空間複雜度卻可以優化到o(n^2)(其實還要再乘以乙個常數)

我們從剛才的三維dp的轉移過程來考慮一下。每次dp都是從上一條對角線上的元素轉移過來,和其他的對角線沒有任何關係,相當於我們在每次dp的時候只需要考慮兩個,乙個是i,乙個是i-1,在i-1之前的其實已經沒有了任何作用。所以我們完全可以廢物再利用。因為每次i的值只改變1,所以可以使用按位與的方法把它變成0或者1,之後直接dp即可,而最後的答案就是dp[(m+n)&1][m][m].這樣空間複雜度又會降一維。本題的資料範圍小,如果資料範圍較大,滾動陣列對於空間的節省就極為有用了。

看一下**。

#include#include

#include

#include

#include

#include

#define rep(i,a,n) for(int i = a;i <= n;i++)

#define per(i,n,a) for(int i = n;i >= a;i--)

#define enter putchar('\n')

using

namespace

std;

typedef

long

long

ll;const

int m = 60

;int n,m,f[m][m],dp[2

][m][m];

intread()

while(ch >='

0' && ch <= '9'

)

return ans *op;

}int

main()}}

printf(

"%d\n

",dp[(n+m)&1

][m][m]);

return0;

}

NOIP2008傳紙條 DP 費用流

在乙個矩形上求兩條不相交的價值最大的路徑 常規dp題,略過 這道題可以作為費用流入門題,可以很好理解費用流的用途 1 找出方案可行 考慮最大流建圖方法 首先因為要找不想交的兩條路徑,我們可以限制每個點只被選擇一次,對於點的限制一般是拆點的套路。將乙個點i拆分為2個點,i和i 並且連邊權為1,這樣就可...

Noip2008傳紙條題解

仍是多執行緒dp,這次直接斜著讀入,方便寫dp方程。以6 4的圖為例,讀入順序如表 從左至右,從上至下,不用管那些0 for int i 1 i m i for int j 1 j n j read map i j 1 i 00 0000 0000 00 1,4 2,4 3,4 4,4 5,4 6,...

動態規劃入門 NOIP2008 傳紙條

小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成乙個m行n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。幸運的是,他們可以通過傳紙條來進行交流。紙條要經由許多同學傳到對方手裡,小淵坐在矩陣的左上角,座標 1,1 小軒坐在矩...