【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;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 剁椒怎么吃 剁椒臭豆腐 剁椒鱼翅 剁椒目鱼仔 剁椒鲢鱼头 剁椒鸡 剁椒烤鱼 剁椒辣椒酱 剁椒鸡肉 剁椒拌面 剁椒昂刺鱼 剁椒茄子 剁椒蒸菜 剁椒猪蹄 剁椒鱼头王 剁椒炒鸡蛋 剁椒鱼头做法 剁椒蒜蓉烤生蚝 剁椒鱼头家常做法 蒜味剁椒炒蛏子 剁椒酱的做法 剁椒鱼头怎么做 湖南剁椒鱼头 家常剁椒蒸鱼头 正宗剁椒鱼头做法 剁椒鱼头蒸多久 剁椒鱼头图片 剁椒鱼头什么鱼 剁椒粉丝蒸娃娃菜 剁椒怎么做制作方法 鲜香剁椒鱼头 剁椒芋头的做法 剁椒芋头做法 剁椒鱼头用什么鱼 剁椒制作方法 剁椒怎么制作方法 清蒸剁椒鱼头 双色剁椒鱼头 正宗剁椒鱼头 剁椒蒸金针菇 剁椒鱼头怎么做好吃