【2017年浙江工业大学大学生程序设计迎新赛决赛】G 取数游戏二【DP or 记忆化DFS】
来源:互联网 发布:女生必知 编辑:程序博客网 时间:2024/06/05 11:14
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
给定两个长度为n的整数列A和B,每次你可以从A数列的左端或右端取走一个数。假设第i次取走的数为ax,则第i次取走的数的价值vi=bi⋅ax,现在希望你求出∑vi的最大值。
输入描述:
第一行一个数T,表示有T组数据。
对于每组数据,第一行一个整数n,
接下来两行分别给出A数列与B数列。
输出描述:
每一组数据输出一行,最大的∑vi。
示例1
输入
2
2
1 1000
2 1
5
1 3 5 2 4
1 2 3 4 5
输出
2001
52
说明
对于第二个样例,
第一次从左边取走a1,v1=a1⋅b1=1,
第二次从左边取走a2,v2=a2⋅b2=6,
第三次从右边取走a5,v3=a5⋅b3=12,
第四次从右边取走a4,v4=a4⋅b4=8,
第五次取走剩下的a3,v5=a3⋅b5=25。
总价值∑vi=1+6+12+8+25=52
备注:
T≤10
1≤n≤103
1≤ai,bi≤103
分析: 取数的过程可以为:
0> 左边取零个,其余都取右边的
1 >左边取一个,其余都取右边的
2> 左边取两个,其余都取右边的
3 >左边取三个,其余都取右边的
…
..
根据这个规律,我们可以用DP来解决,用dp [ i ] [ j ] 来表明 左边取i个,右边取j个能够获得的最大值。
怎么找状态转移方程呢? 我们可以思考一下,对于dp [ i ] [ j ] 这个状态,是能够由那些状态得到的。就可以得到:
状态转移方程 :
dp[ i ] [ j ] = max(dp[ i - 1][ j ] + a[ i ] * b[ j+i ] , dp[ i ][ j -1 ] + a[ n - j +1 ] *b [ j + i ] ) .
根据这个状态转移方程我们可以得到 递推遍历的方向,首先看外层循环,对于dp[ i ] 层来说 是需要dp[ i- 1 ]层来递推,所以我们可知外层循环正向遍历i。同理内层循环 也是要正向遍历j。
代码
#include<bits/stdc++.h>using namespace std;#define LL long longconst int MAXN = 1e3+11;const int MAXM = 1e6 ;const LL mod = 1e9+7 ;int a[MAXN],b[MAXN];int dp[MAXN][MAXN];int main(){ int T ;cin>>T; while(T--){ int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int j=1;j<=n;j++) cin>>b[j]; for(int i=1;i<=n;i++) { // 一直紧着一边拿可得到的最大值 dp[i][0]=dp[i-1][0]+a[i]*b[i]; dp[0][i]=dp[0][i-1]+a[n-i+1]*b[i]; } int ans=0; for(int i=1;i<=n;i++){// 外层正向遍历 for(int j=1;j<=n;j++) { // 内层也要正向遍历 dp[i][j]=max(dp[i-1][j]+a[i]*b[i+j],dp[i][j-1]+a[n-j+1]*b[j+i]) ; if(i+j==n) ans=max(ans,dp[i][j]); } } cout<<ans<<endl; }return 0;}
记忆化DFS
#include<bits/stdc++.h>using namespace std;#define LL long long#define CLOSE() ios_base::sync_with_stdio(false)const int MAXN = 1e3+11;const int MAXM = 1e6 ;const LL mod = 1e9+7 ;int a[MAXN],b[MAXN];int dp[MAXN][MAXN];int dfs(int l,int r,int step){ if(l>r) return 0; if(dp[l][r]) return dp[l][r]; int temp=0; temp=max(temp,dfs(l+1,r,step+1)+b[step]*a[l]); temp=max(temp,dfs(l,r-1,step+1)+b[step]*a[r]); return dp[l][r]=temp;}int main(){ CLOSE(); int T; cin>>T; while(T--){ memset(dp,0,sizeof(dp)); int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) cin>>b[i]; dfs(1,n,1); cout<<dp[1][n]<<endl; }return 0;}