背包问题
01背包
#include <bits/stdc++.h>
using namespace std;
const int N= 1010 ;
int f[ N] ;
int n, m;
int v[ N] , w[ N] ;
int main ( )
{
cin>> n>> m;
for ( int i= 1 ; i<= n; i++ ) cin>> v[ i] >> w[ i] ;
for ( int i= 1 ; i<= n; i++ )
{
for ( int j= m; j>= v[ i] ; j-- )
{
f[ j] = max ( f[ j] , f[ j- v[ i] ] + w[ i] ) ;
}
}
cout<< f[ m] << endl;
return 0 ;
}
完全背包
#include <bits/stdc++.h>
using namespace std;
const int N= 1010 ;
int f[ N] ;
int n, m;
int v[ N] , w[ N] ;
int main ( )
{
cin>> n>> m;
for ( int i= 1 ; i<= n; i++ ) cin>> v[ i] >> w[ i] ;
for ( int i= 1 ; i<= n; i++ )
{
for ( int j= v[ i] ; j<= m; j++ )
{
f[ j] = max ( f[ j] , f[ j- v[ i] ] + w[ i] ) ;
}
}
cout<< f[ m] << endl;
return 0 ;
}
多重背包
#include <bits/stdc++.h>
using namespace std;
const int N= 25000 , M= 2010 ;
int n, m;
int v[ N] , w[ N] ;
int f[ N] ;
int main ( )
{
cin>> n>> m;
int cnt= 0 ;
for ( int i= 1 ; i<= n; i++ )
{
int a, b, s;
cin>> a>> b>> s;
int k= 1 ;
while ( k<= s)
{
cnt++ ;
v[ cnt] = a* k;
w[ cnt] = b* k;
s- = k;
k* = 2 ;
}
if ( s> 0 )
{
cnt++ ;
v[ cnt] = a* s;
w[ cnt] = b* s;
}
}
n= cnt;
for ( int i= 1 ; i<= n; i++ )
{
for ( int j= m; j>= v[ i] ; j-- )
{
f[ j] = max ( f[ j] , f[ j- v[ i] ] + w[ i] ) ;
}
}
cout<< f[ m] << endl;
return 0 ;
}
分组背包
#include <bits/stdc++.h>
using namespace std;
const int N= 110 ;
int n, m;
int v[ N] [ N] , w[ N] [ N] , s[ N] ;
int f[ N] ;
int main ( )
{
cin>> n>> m;
for ( int i= 1 ; i<= n; i++ )
{
cin>> s[ i] ;
for ( int j= 0 ; j< s[ i] ; j++ )
cin>> v[ i] [ j] >> w[ i] [ j] ;
}
for ( int i= 1 ; i<= n; i++ )
for ( int j= m; j>= 0 ; j-- )
for ( int k= 0 ; k< s[ i] ; k++ )
if ( v[ i] [ k] <= j)
f[ j] = max ( f[ j] , f[ j- v[ i] [ k] ] + w[ i] [ k] ) ;
cout<< f[ m] << endl;
return 0 ;
}
线性dp
数字三角形
在这里插入代码片
最长上升子序列
#include <bits/stdc++.h>
using namespace std;
const int N= 1010 ;
int n;
int a[ N] , f[ N] ;
int main ( )
{
scanf ( "%d" , & n) ;
for ( int i= 1 ; i<= n; i++ ) scanf ( "%d" , & a[ i] ) ;
for ( int i= 1 ; i<= n; i++ )
{
f[ i] = 1 ;
for ( int j= 1 ; j< i; j++ )
{
if ( a[ j] < a[ i] )
{
f[ i] = max ( f[ i] , f[ j] + 1 ) ;
}
}
}
int res= 0 ;
for ( int i= 1 ; i<= n; i++ ) res= max ( res, f[ i] ) ;
cout<< res<< endl;
return 0 ;
}
最长公共子序列
#include <bits/stdc++.h>
using namespace std;
const int N= 1010 ;
int n, m;
char a[ N] , b[ N] ;
int f[ N] [ N] ;
int main ( )
{
cin>> n>> m>> a+ 1 >> b+ 1 ;
for ( int i= 1 ; i<= n; i++ )
{
for ( int j= 1 ; j<= m; j++ )
{
f[ i] [ j] = max ( f[ i- 1 ] [ j] , f[ i] [ j- 1 ] ) ;
if ( a[ i] == b[ j] ) f[ i] [ j] = max ( f[ i] [ j] , f[ i- 1 ] [ j- 1 ] + 1 ) ;
}
}
cout<< f[ n] [ m] << endl;
return 0 ;
}
区间dp
#include <bits/stdc++.h>
using namespace std;
const int N= 310 ;
int n;
int s[ N] ;
int f[ N] [ N] ;
int main ( )
{
cin>> n;
for ( int i= 1 ; i<= n; i++ ) cin>> s[ i] ;
for ( int i= 1 ; i<= n; i++ ) s[ i] + = s[ i- 1 ] ;
for ( int len= 2 ; len<= n; len++ )
{
for ( int i= 1 ; i+ len- 1 <= n; i++ )
{
int l= i, r= i+ len- 1 ;
f[ l] [ r] = 1e8 ;
for ( int k= l; k< r; k++ )
f[ l] [ r] = min ( f[ l] [ r] , f[ l] [ k] + f[ k+ 1 ] [ r] + s[ r] - s[ l- 1 ] ) ;
}
}
cout<< f[ 1 ] [ n] << endl;
return 0 ;
}
状压dp
在这里插入代码片
计数dp
状态机
记忆化搜索
#include <bits/stdc++.h>
using namespace std;
const int N = 310 ;
int n, m;
int h[ N] [ N] ;
int f[ N] [ N] ;
int dx[ 4 ] = { - 1 , 0 , 1 , 0 } ;
int dy[ 4 ] = { 0 , 1 , 0 , - 1 } ;
int dp ( int x, int y) {
int & v = f[ x] [ y] ;
if ( v != - 1 ) return v;
v = 1 ;
for ( int i = 0 ; i < 4 ; i ++ ) {
int a = x + dx[ i] , b = y + dy[ i] ;
if ( a >= 1 && a <= n && b >= 1 && b <= m && h[ a] [ b] < h[ x] [ y] ) {
v = max ( v, dp ( a, b) + 1 ) ;
}
}
return v;
}
int main ( ) {
scanf ( "%d%d" , & n, & m) ;
for ( int i = 1 ; i <= n; i ++ ) {
for ( int j = 1 ; j <= m; j ++ ) {
scanf ( "%d" , & h[ i] [ j] ) ;
}
}
memset ( f, - 1 , sizeof f) ;
int res = 0 ;
for ( int i = 1 ; i <= n; i ++ ) {
for ( int j = 1 ; j <= m; j ++ ) {
res = max ( res, dp ( i, j) ) ;
}
}
printf ( "%d\n" , res) ;
return 0 ;
}