码迷,mamicode.com
首页 > 其他好文 > 详细

【专章】dp基础

时间:2017-10-04 21:13:25      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:main   res   mic   close   合并   org   turn   size   microsoft   

知识储备:dp入门

好了,完成了dp入门,我们可以做一些稍微不是那么裸的题了。

------------------------------------------------------------------------------------

洛谷P1880 石子合并

分析:曾经的noi系列。石子合并问题分好几种情况。

这题是环形的,且只能合并相邻的两堆,那么我们把石子数组展开,如[1,2,3,4,5] -> [1,2,3,4,5,1,2,3,4,5],这样进行处理,就能将环形转换成直线。

转换完之后,就可以用dp做了,dp的解释详见代码。这题数据过得去,时间是 O(n3) 不然要用平行四边形优化。

安利一发acdreamer的博客,把石子合并问题讲的很清楚http://blog.csdn.net/acdreamers/article/details/18039073

技术分享
 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 int sum[205],mins[205][205],maxs[205][205],s[205][205];//dp[i][j]=i~j的最大得分
 5 int main()
 6 {
 7     int  a,n,minnum=9999999,maxnum=-minnum;
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;i++)
10     {
11         scanf("%d",&sum[i]);
12         sum[i+n]=sum[i];
13         s[i][i]=i;
14         s[i*2][i*2]=i;
15     }
16     for(int i=1;i<=2*n;i++) sum[i]+=sum[i-1]; //前缀和 
17     for(int l=1;l<=n;l++)//区间长度
18     {
19         for(int i=1;i+l<=2*n;i++)//开始的端点 
20         {
21             
22             int j=i+l;//结束的端点
23             maxs[i][j]=-99999999;mins[i][j]=-1*maxs[i][j];
24             for(int k=i;k<j;k++)
25             {
26                 maxs[i][j]=max(maxs[i][j],maxs[i][k]+maxs[k+1][j]+sum[j]-sum[i-1]);
27                 mins[i][j]=min(mins[i][j],mins[i][k]+mins[k+1][j]+sum[j]-sum[i-1]);
28             }
29         }
30     } 
31     for(int i=1;i<=n;i++)//因为是环形的,可从任意两堆间分开,所以需要枚举一遍起点从1~n 
32     {
33         maxnum=max(maxs[i][i+n-1],maxnum);
34         minnum=min(mins[i][i+n-1],minnum);
35     }
36     printf("%d\n%d",minnum,maxnum);
37     return 0;
38 } 
View Code

 

洛谷P1108 低价购买

分析:第一问还是很简单的,求最长下降子序列。第二问要计算方案数量,还要判重。

用t[i]表示前i个股票的不同方案个数,可以得出,如果存在dp[j]==dp[i] && a[j]==a[i]方案就是重复的,所以就把t[i]赋为0,如果f[i]==f[j]+1,那么i可以从j转移,所以t[i]+=t[j]。最后统计和即可。

 

技术分享
 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 int dp[5005],a[5005],t[5005];//t,计算出现次数的dp 
 5 int main()
 6 {
 7     int ans=-99999,n,k=0,res=0;
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
10     for(int i=1;i<=n;i++)
11     {
12         dp[i]=1;
13         for(int j=1;j<i;j++)
14         {
15             if(a[j]>a[i]) dp[i]=max(dp[i],dp[j]+1);
16         }
17         ans=max(ans,dp[i]);
18     }
19     for(int i=1;i<=n;i++)
20     {
21         if(dp[i]==1) t[i]=1;//如果无法转移则为1 
22         for(int j=1;j<i;j++)
23         {
24             if(dp[j]==dp[i]-1 && a[i]<a[j])//判前继 判可以为下一个数 
25             {
26                 t[i]+=t[j];//转移
27             }
28             else if(dp[i]==dp[j]&&a[i]==a[j]) t[j]=0;//判重
29         }
30     }
31     for(int i=1;i<=n;i++)
32     {
33         if(dp[i]==ans) res+=t[i];
34     }
35     printf("%d %d",ans,res);
36     return 0;
37 }
View Code

 

【专章】dp基础

标签:main   res   mic   close   合并   org   turn   size   microsoft   

原文地址:http://www.cnblogs.com/noblex/p/7627129.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!