【P1464 Function】
【题解】
按照题目意思进行递归即可,但是过程中需要用到记忆化搜索。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll dp[50][50][50]; 5 ll w(ll a,ll b,ll c){ 6 if(a<=0||b<=0||c<=0){return 1;} 7 if(a>20||b>20||c>20){return w(20,20,20);} 8 if(a<b&&b<c){ 9 if(dp[a][b][c-1]==0) dp[a][b][c-1]=w(a,b,c-1); 10 if(dp[a][b-1][c-1]==0) dp[a][b-1][c-1]=w(a,b-1,c-1); 11 if(dp[a][b-1][c]==0) dp[a][b-1][c]=w(a,b-1,c); 12 return dp[a][b][c]=dp[a][b][c-1]+dp[a][b-1][c-1]-dp[a][b-1][c]; 13 }else{ 14 if(dp[a-1][b][c]==0)dp[a-1][b][c]=w(a-1,b,c); 15 if(dp[a-1][b-1][c]==0)dp[a-1][b-1][c]=w(a-1,b-1,c); 16 if(dp[a-1][b][c-1]==0)dp[a-1][b][c-1]=w(a-1,b,c-1); 17 if(dp[a-1][b-1][c-1]==0)dp[a-1][b-1][c-1]=w(a-1,b-1,c-1); 18 return dp[a][b][c] 19 =dp[a-1][b][c] 20 +dp[a-1][b-1][c] 21 +dp[a-1][b][c-1] 22 -dp[a-1][b-1][c-1]; 23 } 24 } 25 int main() 26 { 27 ll a,b,c; 28 while(~scanf("%lld%lld%lld",&a,&b,&c)){ 29 if(a==-1&&b==-1&&c==-1){ 30 break; 31 } 32 ll ans=w(a,b,c); 33 printf("w(%lld, %lld, %lld) = %lld ",a,b,c,ans); 34 } 35 return 0; 36 }
【P1002 过河卒】
【题解】
其实就是马的位置和马口的位置方案为0,无法转移,其他情况照常即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 30 ; 5 ll dp[N][N]; 6 int dir[9][2] = { 7 {-2,-1} , {-2,1}, 8 {-1,-2}, {-1,2}, 9 {0,0}, 10 {1,-2}, {1,2}, 11 {2,-1}, {2,1} 12 }; 13 int main() 14 { 15 int n,m,x,y; 16 cin >> n >> m >> x >> y ; 17 n ++ , m ++ , x ++ , y ++ ; 18 dp[1][1] = 1 ; 19 for(int i=1;i<=n;i++){ 20 for(int j=1;j<=m;j++){ 21 if( i == 1 && j == 1 ) continue ; 22 bool f = true; 23 for(int k=0;k<9;k++){ 24 if( i == x + dir[k][0] && j == y + dir[k][1] ) 25 f = false ; 26 } 27 if( f ) 28 dp[i][j] = dp[i-1][j] + dp[i][j-1]; 29 } 30 } 31 32 printf("%lld ",dp[n][m]); 33 return 0; 34 35 }
【P1004 方格取数】
【题解】
这个题目和传纸条一样,开4维,分别枚举两个人在两个维度上同时跑动获取最大值的情况综合即可,
这个题目比传纸条更简单的是一个点可以经过两次 并且确保两个维度的曼哈顿距离相同。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 12 ; 4 int G[N][N],n,u,v,w; 5 int dp[N][N][N][N]; 6 int main() 7 { 8 ios_base :: sync_with_stdio(false); 9 cin.tie(NULL),cout.tie(NULL); 10 11 cin >> n ; 12 13 while ( cin >> u >> v >> w , (u+v+w) ){ 14 G[u][v] = w ; 15 } 16 17 for(int x1=1;x1<=n;x1++){ 18 for(int y1=1;y1<=n;y1++){ 19 for(int x2=1;x2<=n;x2++){ 20 for(int y2=1;y2<=n;y2++){ 21 22 23 if( !( x1 == n && y1 == n ) && ( x1 + y1 != x2 + y2 ) ) 24 continue ; 25 26 int tmp = 0 ; 27 /*if( ( !(x1 == x2 && y1 == y2) ) || 28 ( (x1 == x2 && y1 == y2) && (x1 == n && y1 == n) ) ){ 29 */ 30 tmp = max( tmp , dp[x1-1][y1][x2-1][y2] ); 31 tmp = max( tmp , dp[x1-1][y1][x2][y2-1] ); 32 tmp = max( tmp , dp[x1][y1-1][x2-1][y2] ); 33 tmp = max( tmp , dp[x1][y1-1][x2][y2-1] ); 34 35 dp[x1][y1][x2][y2] = tmp + G[x1][y1] + G[x2][y2] ; 36 if( x1 == x2 && y1 == y2 ){ 37 dp[x1][y1][x2][y2] = dp[x1][y1][x2][y2] - G[x1][y1]; 38 } 39 //} 40 } 41 } 42 } 43 } 44 cout << dp[n][n][n][n] << endl; 45 return 0; 46 }
【P1006 传纸条】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 51; 4 int dp[N][N][N][N],G[N][N]; 5 int n,m; 6 int main() 7 { 8 ios_base :: sync_with_stdio(false); 9 cin.tie(NULL) , cout.tie(NULL); 10 cin >> n >> m ; 11 for(int i=1;i<=n;i++) 12 for(int j=1;j<=m;j++) 13 cin >> G[i][j] ; 14 for(int x1=1;x1<=n;x1++){ 15 for(int y1=1;y1<=m;y1++){ 16 for(int x2=1;x2<=n;x2++){ 17 for(int y2=1;y2<=m;y2++){ 18 //如果没有达到终点,那么左下角是(x1,y1),右上角就是(x2,y2) 19 20 //这句话就是,如果过程中出现 步数不相符的情况,也就是说两者同时跑。不出现一个走10步,另一个走1步 21 //if( !( x1 == n && y1 == m ) && ( x1 < x2 && y1 < y2 ) ) 22 if( !( x1 == n && y1 == m ) && ( x1 + y1 != x2 + y2 ) ) 23 continue ; 24 25 // 更新的时候,过程中 不能存在两者都在同一个点的情况。 26 if( ( x1 == n && y1 == m && x1==x2 && y1==y2 ) 27 || !( x1 == x2 && y1 == y2) ){ 28 int tmp = 0 ; 29 tmp = max ( tmp , dp[x1-1][y1][x2-1][y2] ); 30 tmp = max ( tmp , dp[x1-1][y1][x2][y2-1] ); 31 tmp = max ( tmp , dp[x1][y1-1][x2-1][y2] ); 32 tmp = max ( tmp , dp[x1][y1-1][x2][y2-1] ); 33 34 dp[x1][y1][x2][y2] = tmp + G[x1][y1] + G[x2][y2] ; 35 } 36 } 37 } 38 } 39 } 40 41 cout << dp[n][m][n][m] << endl; 42 return 0; 43 }
【P1005 矩阵取数游戏】
【题意】
每一行拿m次,然后再拿n行,每一行的拿法都一样,拿左右端次序和对应的价值乘积最大。
考虑区间dp。
f[L][R],在取L,R这一段之前 两端取得的最大值
f[L][R] = max{ f[L-1][R] +a[L] * 2 ^(m+L-R-1) , f[L][R+1] + a[R] * 2^(m+L-R-1) }
最后还需要对于每一个单独的f[i][i]拿一遍,因为状态转移没有考虑长度为1的情况。
过程中还需要用到高精度,
高精度需要:
1、高精度+高精度
2、高精度×低精度
3、max{ 高精度,高精度}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int mod = 1e4 ; // 10000 4 const int N = 85; 5 6 7 typedef struct High_precision{ 8 int Len , p[N] ; 9 High_precision() { 10 Len = 0 ; 11 memset( p , 0 , sizeof p) ; 12 } 13 14 void Print(){ 15 printf("%d",p[Len]); 16 for(int i = Len-1 ; i >= 1 ;i--){ 17 printf("%04d",p[i]); 18 } 19 puts(""); 20 } 21 }Hp; 22 23 Hp operator + (const Hp& A , const Hp& B ){ 24 int Len = max( A.Len , B.Len ); 25 Hp C ; 26 int Carry = 0 ; 27 for(int i=1 ; i<=Len ; i++ ){ 28 C.p[i] = ( A.p[i] + B.p[i] + Carry ) ; 29 Carry = (C.p[i]) / mod ; 30 C.p[i] = C.p[i] % mod ; 31 } 32 C.Len = Len ; 33 if( Carry ){ 34 C.p[++C.Len] = Carry ; 35 } 36 return C ; 37 } 38 39 Hp operator * (const Hp& A , const int B ){ 40 Hp C ; 41 int Len = A.Len ; 42 int Carry = 0 ; 43 for(int i = 1 ; i <= Len ; i ++ ){ 44 C.p[i] = A.p[i] * B + Carry ; 45 Carry = C.p[i] / mod ; 46 C.p[i] = C.p[i] % mod ; 47 //C.p[i] = ( A.p[i] * B + Carry ) % mod ; 48 //Carry = ( A.p[i] * B + Carry ) / mod ; 49 } 50 C.Len = A.Len ; 51 while( Carry > 0 ){ 52 C.p[++C.Len] = Carry % mod ; Carry = Carry / mod ; 53 } 54 55 return C ; 56 } 57 58 Hp Max( const Hp& A, const Hp& B ){ 59 int LA = A.Len , LB = B.Len ; 60 if( A.Len > B.Len ) return A ; 61 else if( B.Len > A.Len ) return B ; 62 for(int i=A.Len ; i>=1;i--){ 63 if( A.p[i] > B.p[i] ) return A ; 64 else if( B.p[i] > A.p[i] ) return B ; 65 } 66 return A ; 67 } 68 69 Hp f[N][N] , Base[N] ; 70 int a[N] ; 71 int n,m; 72 73 void Init(){ 74 Base[0].p[1] = 1 ; 75 Base[0].Len = 1 ; 76 for(int i=1;i<=m+2;i++) 77 Base[i] = Base[i-1] * 2 ; 78 79 } 80 81 int main() 82 { 83 84 scanf("%d%d",&n,&m); 85 Hp Ans , tmp ; 86 87 Init(); 88 //Base[20].Print(); 89 90 for(int i=1;i<=n;i++){ 91 for(int j=1;j<=m;j++){ 92 scanf("%d",&a[j]); 93 f[j][j].p[1] = a[j] ; 94 f[j][j].Len = 1 ; 95 //f[j][j].Print(); 96 //tmp = Max ( tmp , f[j][j] ); 97 } 98 memset( f , 0 , sizeof f );//别忘了 99 100 //cout << " ### " ; tmp.Print(); 101 for( int L = 1 ; L <= m ; L++ ){ 102 for( int R = m ; R >= L ; R-- ){ 103 f[L][R] = Max( f[L-1][R] + Base[m+L-R-1] * a[L-1] , f[L][R] ); 104 f[L][R] = Max( f[L][R+1] + Base[m+L-R-1] * a[R+1] , f[L][R] ); 105 } 106 } 107 tmp.Len = 1 ; 108 tmp.p[1] = 0 ; 109 for( int j = 1 ; j <= m ;j++ ){ 110 tmp = Max ( tmp , f[j][j] + Base[m] * a[j] ) ; 111 } 112 113 //cout << " ### " ; tmp.Print(); 114 115 Ans = Ans + tmp ; 116 } 117 118 Ans.Print(); 119 return 0; 120 } 121 122 /* 123 2 3 124 1 2 3 125 3 4 2 126 127 */
【P1049 装箱问题】
【题解】01背包
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 25000 ; 4 int dp[N]; 5 int main() 6 { 7 int V , n ; 8 cin >> V >> n ; 9 10 for(int i=1,v;i<=n;i++){ 11 scanf("%d",&v); 12 for(int j=V;j>=v;j--){ 13 dp[j] = max(dp[j],dp[j-v]+v); 14 } 15 } 16 printf("%d ",V-dp[V]); 17 return 0; 18 }
【P1541 乌龟棋】
【感受】
当我做这个题目的时候不得不佩服当初杨宗耀是真NB,可能大家都想不出来的,他都能做出来,当初我觉得他写的四维DP也太难想到了吧,后来就想到了,而且做出来了。我真的佩服至今。
【题解】
考虑四个维度每一个维度都用了多少张牌,然后通过状态转移过来即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 355; 5 const int M = 41; 6 int dp[M][M][M][M],a[N]; 7 int n,m; 8 int main(){ 9 scanf("%d%d",&n,&m); 10 11 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 12 13 dp[0][0][0][0] = a[1] ; 14 int cnt = 0 ; 15 int One = 0 , Two = 0 , Three = 0 , Four = 0 ; 16 for(int i=1,w;i<=m;i++){ 17 scanf("%d",&w); 18 if( w == 1 ) One ++ ; 19 else if( w == 2 ) Two ++ ; 20 else if( w == 3 ) Three ++ ; 21 else if( w == 4 ) Four ++ ; 22 } 23 for(int o=0;o<=One;o++){ 24 for(int t=0;t<=Two;t++){ 25 for(int th=0;th<=Three;th++){ 26 for(int f=0;f<=Four ;f++){ 27 28 int dis = 1+ o + t*2 + th*3 + f*4 ; 29 if( f >= 1 ){ 30 dp[o][t][th][f] = 31 max( dp[o][t][th][f-1] + a[dis] 32 , dp[o][t][th][f] ); 33 } 34 if( th >= 1 ){ 35 36 dp[o][t][th][f] = 37 max( dp[o][t][th-1][f] + a[dis] 38 , dp[o][t][th][f]); 39 } 40 if( t >= 1 ){ 41 dp[o][t][th][f] = 42 max( dp[o][t-1][th][f] + a[dis] 43 , dp[o][t][th][f]); 44 } 45 if( o >= 1 ){ 46 dp[o][t][th][f] = 47 max( dp[o-1][t][th][f] + a[dis] 48 , dp[o][t][th][f]); 49 } 50 } 51 } 52 } 53 } 54 printf("%d ",dp[One][Two][Three][Four]); 55 return 0; 56 }
【P1048 采药】
【题解】
01背包模板题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e4+10; 4 int dp[N]; 5 int main() 6 { 7 int V,n; 8 cin >> V >> n ; 9 for(int i=1,v,w;i<=n;i++){ 10 cin >> v >> w ; 11 for(int j=V;j>=v;j--){ 12 dp[j] = max( dp[j] , dp[j-v]+w); 13 } 14 } 15 cout << dp[V] << endl; 16 return 0; 17 }