openjudge动规刷题攻略----第一弹
来源:互联网 发布:newsql数据库有哪些 编辑:程序博客网 时间:2024/06/06 15:36
基本算法之动态规划(1~4)
1481 Maximumsum
题目大意:求两个最大连续子序列和的和。
解题思路
搞起来很玄妙,正序、倒序分别来一遍DP:
sum_1[i]表示前i个数里的最大连续子序列和,sum_2[i]表示后i个数里的最大连续子序列和。至于为啥这样跑……反正我是想不出更好的方法了。t1存的是包含当前数a[i]的最大序列和,而t2存的是sum_1[i],每次先更新t1再更新t2。
参考代码
int t1=-21000,t2=0;
for (int i=1;i<=n;i++)
{
if (t2>0) t2+=a[i];
else t2=a[i];
t1=max(t1,t2);
sum_1[i]=t1;
}
t1=-210000,t2=0;
for (int i=n;i;i--)
{
if (t2>0) t2+=a[i];
else t2=a[i];
t1=max(t1,t2);
sum_2[i]=t1;
}
int ans=sum_1[1]+sum_2[2];
for (int i=2;i<n;i++)
if (sum_1[i]+sum_2[i+1]>ans)
ans=sum_1[i]+sum_2[i+1];
162 Post Office
题目大意:给定一个整数n和一个整数k,给出n个位置坐标,在这n个位置里选k个位置作为邮局,使这n个位置到最近的邮局的距离和最小。
解题思路
先预处理出每个子区间内建一个邮局的最小距离和(贪心,取最中间的点作为邮局),然后跑DP:f[i][k]表示前i个点建k个邮局的最小距离和,枚举断点j(i<=j<i),将j~i部分看作一个子区间,建一个邮局,很容易得到转移方程:
f[i][k]=min(f[j][k-1]+s[j+1][i])(1<=j<i)
参考代码
for (int i=1;i<=n;i++)s[i][i]=0;
for(int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
{
int mid=pos[(i+j)/2];
int sum=0;
for (int k=i;k<=j;k++)
sum+=abs(mid-pos[k]);
s[i][j]=sum;
}
memset(f,0x3f,sizeof(f));
for (int i=1;i<=n;i++)
f[i][1]=s[1][i];
for (int k=2;k<=kk;k++)
{
for (int i=k;i<=n;i++)
for (int j=1;j<i;j++)
if (j>=k-1)
f[i][k]=min(f[i][k],f[j][k-1]+s[j+1][i]);
}
1759最长上升子序列
解题思路
贴一个nlogn做法的代码,详情参考神犇博客:
http://blog.csdn.net/wall_f/article/details/8295812
参考代码
int s[1005],a[1005];
int ef(int l,int r,int st)
{
while (l<=r)
{
int mid=(l+r)/2;
if (s[mid]<st) l=mid+1;
else r=mid-1;
}
return l;
}
int main()
{
memset(s,0x3f,sizeof(s));
//s[i]表示长度为i的序列末尾数字的最小值;
int n;
cin>>n;
for (int i=1;i<=n;i++)
cin>>a[i];
int ans=0;
for (int i=1;i<=n;i++)
{
int pos=ef(1,i,a[i]);
//返回末位数字恰好比a[i]大的序列长度;
s[pos]=min(s[pos],a[i]);
ans=max(ans,pos);
//更新最大序列长度;
}
cout<<ans;
return 0;
}
1786 最大子矩阵
解题思路
四重循环现在都不敢写了……f[i][j]表示以(i,j)为右下角的矩阵里的最大子矩阵,但预处理只能求出(0,0)为左上角的情况,所以需要枚举一个点(k,l)。下图中蓝+灰、紫+灰的部分是可以枚举的,而且一定在之前处理过,我们的目标是求右下角的那一小块的和,然后和f[i][j]比较取较大值,然后和ans取较大值作为结果。预处理的时候其实也有DP的思想。
参考代码
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
cin>>a[i][j];
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
}
memset(f,0,sizeof(f));
int ans=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=0;k<i;k++)
for (int l=0;l<j;l++)
{
f[i][j]=max(f[i][j],s[i][j]-s[i][l]-s[k][j]+s[k][l]);
if (f[i][j]>ans) ans=f[i][j];
}
- openjudge动规刷题攻略----第一弹
- openjudge动规刷题攻略---第2弹
- OpenJudge
- 第一个opengl程序完整攻略
- Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略
- Android 弹无虚发之第一弹:Android 2.X平台完美兼容ActionBar以及Actionbar的常用攻略
- 创业北京全攻略:从零开始到开具第一张发票
- 【攻略】淘宝前端智勇大闯关-第一季
- VillaEscape(别墅逃亡)第一关通关攻略
- [OpenJudge]胡
- OPENJUDGE LIST
- OPENJUDGE SET
- openjudge 迷宫
- openjudge 2764
- 【openjudge】Minecraft
- 【openjudge】登山
- 【openjudge】股票买卖
- 【openjudge】大盗阿福
- 1063. Set Similarity
- php与前端(三):下拉框搜索 select2 的使用
- Android 项目中添加一个新类,无法在其它类中使用
- c++ 数据结构 双向循环链表
- Javascript 高级 ajax 、jsonp
- openjudge动规刷题攻略----第一弹
- Python进阶-连接 Mysql
- Find The Multiple poj1426 (DFS)
- Spark-RDD编程基础
- weka连接mysql
- java : Iterator Pattern
- Android创建原图的副本
- 非root下,如何将android中的数据库文件存放到外部存储并导出
- 学习classList写的小Demo