1027 取数游戏2 线性DP| 区间DP | dfs
链接:https://ac.nowcoder.com/acm/problem/14701
来源:牛客网
题目描述
输入描述:
第一行一个数T,表示有T组数据。
对于每组数据,第一行一个整数n,
接下来两行分别给出A数列与B数列。
输出描述:
每一组数据输出一行,最大的∑vi
。
备注:
分析
线性DP
随着选择的数增多,选择左边的数会增多,选择右边的数也会增多,设变量f[k][i][j] 为总共选择了k个数,左边选择了i个数,右边选择了j个数的最大权值
状态转移方程:
1.选择左边:f[k][i][j] = max(f[k-1][i][j],f[k-1][i-1][j] + a[i] * b[i+j])
2.选择右边:f[k][i][j] = max(f[k-1][i][j],f[k-1][i][j-1] + a[n-j+1] * b[i+j])
由于k对表达式结果并没有影响,省去一维
//-------------------------代码---------------------------- //#define int LL const int N = 1100; int n,m; int a[N],b[N]; int f[N][N]; void solve() { cin>>n; memset(f,0,sizeof f); fo(i,1,n) cin>>a[i]; fo(i,1,n) cin>>b[i]; fo(i,1,n) { f[i][0] = f[i-1][0] + a[i] * b[i]; f[0][i] = f[0][i-1] + a[n-i+1] * b[i]; } int ans = 0; fo(i,1,n) { fo(j,1,n) { f[i][j] = max(f[i-1][j] + a[i] * b[i + j], f[i][j-1] + a[n-j+1] * b[i+j]); if(i + j == n) ans = max(ans,f[i][j]); } } cout<<ans<<endl; } signed main(){ clapping();TLE; int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------
-------------------------------------------------------------分界线----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
分析
如果把删除数的过程倒过来看,就变成增加数的过程,这时候从小区间到大区间的区间DP思路就很直观了
设f[i][j] 表示的是取区间[i,j] 的最大取值,区间大小是j - i + 1,从1逐渐变大到n
状态转移:f[i][j] = max(f[i+1][j] + a[i] * b[n-k+1],f[i][j-1] + a[j] * b[n-k+1]);k表示的是区间大小
//-------------------------代码---------------------------- #define int LL const int N = 1100; int n,m; int a[N],b[N]; int f[N][N]; void solve() { cin>>n; memset(f,0,sizeof f); fo(i,1,n) cin>>a[i]; fo(i,1,n) cin>>b[i]; for(int i=1;i<=n;i++) { for(int j=1;i+j-1<=n;j++) { int k=i+j-1; f[j][k]=max(f[j][k],max(f[j][k-1]+a[k]*b[n-i+1],f[j+1][k]+a[j]*b[n-i+1])); } } cout<<f[1][n]<<endl; } signed main(){ clapping();TLE; int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------
/*样例区
*/
//------------------------------------------------------------
分析
写成dfs,真的会更直观,dfs 的记忆化搜索和线性DP以及区间DP都有点异曲同工之妙
基本思路是一样的,只是dfs更直观,差点把dfs怎么写给忘了
//-------------------------代码---------------------------- #define int LL const int N = 1100; int n,m; int a[N],b[N]; int dp[N][N]; int dfs(int l,int r,int i) { if(i==n+1)return 0; if(dp[l][r]!=0)return dp[l][r]; return dp[l][r]=max(dfs(l+1,r,i+1)+b[i]*a[l],dfs(l,r-1,i+1)+b[i]*a[r]); } void solve() { cin>>n; memset(dp,0,sizeof dp); fo(i,1,n) cin>>a[i]; fo(i,1,n) cin>>b[i]; cout<<dfs(1,n,1)<<endl; } signed main(){ clapping();TLE; int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------