数字三角形
经典例题,有记忆化搜索,正推,逆推三种方法
如果记录路径,可以开一个数组记录状态是由哪个子状态推出来的
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 200; int n,dp[maxn][maxn],value[maxn][maxn]; int main(){ cin>>n; for(int i = 1;i <=n;i++){ for(int j = 1;j <= i;j++){ cin>>value[i][j]; } } memset(dp,-1,sizeof(dp)); for(int i = 1;i <= n;i++) dp[n][i] = value[n][i]; for(int i = n - 1;i >= 1;i--){ for(int j = 1;j <= i;j++){ dp[i][j] = value[i][j] + max(dp[i+1][j],dp[i+1][j+1]); } } cout<<dp[1][1]; return 0; }
数字三角形w
同数字三角形,要求数字总和取模100后最大,既然总和大的余数不一定大,所以转化为可行性判断
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,dp[50][50][105],map[50][50],ans = 0; int x,y; int main(){ cin>>n; for(int i = 1;i <= n;i++){ for(int j = 1;j <= i;j++){ scanf("%d",&map[i][j]); } } dp[1][1][map[1][1]%100] = 1; for(int i = 2;i <= n;i++){ for(int j = 1;j <= i;j++){ for(int k = 0;k <= 99;k++){ if(dp[i-1][j-1][k] || dp[i-1][j][k]){ dp[i][j][(k+map[i][j])%100] = 1; if(i == n) ans = max(ans,(k+map[i][j])%100); } } } } cout<<ans; return 0; }
数字三角形ww
同数字三角形,要求必须经过x div 2,y div 2这个点
有一个技巧,把这个点的值加上一个特别大的数,就一定会经过这个点
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,dp[50][50],map[50][50],ans = 0,hehe = 100000000; int main(){ cin>>n; for(int i = 1;i <= n;i++){ for(int j = 1;j <= i;j++){ scanf("%d",&map[i][j]); } } map[n/2][n/2] += hehe; for(int i = 1;i <= n;i++){ for(int j = 1;j <= i;j++){ dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]) + map[i][j]; ans = max(dp[i][j],ans); } } cout<<ans-hehe; return 0; }
数字三角形www
同上个题,只不过必过点任意
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,dp[50][50],map[50][50],ans = 0,hehe = 100000000; int x,y; int main(){ cin>>n; for(int i = 1;i <= n;i++){ for(int j = 1;j <= i;j++){ scanf("%d",&map[i][j]); } } cin>>x>>y; map[x][y] += hehe; for(int i = 1;i <= n;i++){ for(int j = 1;j <= i;j++){ dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]) + map[i][j]; ans = max(dp[i][j],ans); } } cout<<ans-hehe; return 0; }
最低通行费用
从左上角到右下角,往右或往下走,使沿途的权值和最小
一定要注意边界的问题
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; int main(){ int map[105][105],dp[105][105],n; cin>>n; for(int i = 1;i <= n;i++){ for(int j = 1;j <= n;j++){ cin>>map[i][j]; } } for(int i = 1;i <= n;i++){ for(int j = 1;j <= n;j++){ if(i > 1 && j > 1)dp[i][j] = map[i][j] + min(dp[i-1][j],dp[i][j-1]); else if(i > 1 && j == 1) dp[i][j] = map[i][j] + dp[i-1][j]; else if(j > 1 && i == 1) dp[i][j] = map[i][j] + dp[i][j-1]; else dp[i][j] = map[i][j]; } } cout<<dp[n][n]; return 0; }