acm每周总结
这个星期我们学习了区间dp,通过本周学习我总结一下,这种题型的解题思路。
1.区间长度定义
2.定左端点(通过左端点定右端点)
3.在子区间里寻找分界点并考虑区间dp动态方程,说实话(我认为只要把例子中从区间长度为三推到四,基本上就可以大致推出dp动态规划方程)
4.base case(这个也很重要,好的初始设置是成功解题的关键,可以省很多事)
原始代码
base case
dp[][]=
for(int len=;len<=n;len++)
{for(int r=1,l=len;l<n;l++,r++)
{for(int k=r;k<l;k++)
{dp方程;}}}
例题vjq
一条直线上有n个石子,两两合并问,所合并的最大和最小值。
Sample Input
3
1 2 3
Sample Output
9 11
解题思路
1.根据区间dp思路思考
dp方程
dp1[l][r]=max(dp1[l][r],dp1[l][k]+dp1[k+1][r]+sum[r]-sum[l-1]);
dp2[l][r]=min(dp2[l][r],dp2[l][k]+dp2[k+1][r]+sum[r]-sum[l-1])
即每次和
dp[l][r]=max/min(dp[l][r],dp[l][k]+dp1[k+1][r]+合并花费值);
合并花费值只需将左端点的总花费减右端点即可
2.base case的确定
memset(dp2,0x3f3f3f3f3f,sizeof(dp2));
memset(dp1,0,sizeof(dp1));
memset(sum,0,sizeof(sum));
r=l时dp[r][l]=0
代码实现
#include
#include
#include
using namespace std;
long long a[105],sum[105],f1[105][105],f2[105][105];
int n;
int main()
{
while(cin>>n)
{memset(f2,0x3f3f3f3f3f,sizeof(f2));
memset(f1,0,sizeof(f1));
memset(sum,0,sizeof(sum));
for(int q=1;q<=n;q++)
{cin>>a[q];
sum[q]=sum[q-1]+a[q];
f2[q][q]=0;
f1[q][q]=0;
}
for(int q=1;q<n;q++)
{for(int w=1;w<=n-q;w++)
{int r=w+q;
for(int e=w;e<r;e++)
{f1[w][r]=max(f1[w][r],f1[w][e]+f1[e+1][r]+sum[r]-sum[w-1]);
f2[w][r]=min(f2[w][r],f2[w][e]+f2[e+1][r]+sum[r]-sum[w-1]);}}
}
long long maxx=f1[1][n];
long long minn=f2[1][n];
cout<<minn<<" "<<maxx<<endl;
}
return 0;
}
环形问题思路
这是本周遇到的一个典型的问题只需在
数组输出时在后将数在遍历一遍即可,并考虑在直线基础上区间取值的改动