POJ 2586 - 贪心 or DP

来源:互联网 发布:微商的发展前景数据 编辑:程序博客网 时间:2024/05/22 03:08

1.Question:

有一个公司,12个月份,所有的连续的5个月都是亏损的,请求出在此情况下的一年最大的盈利数目,如果没有输出Defict
输入:n,d分别代表每个月的固定的收入和固定的亏损

2.Solution:

相比较而言,DP的思路更快:DP 0ms   贪心16ms
本题我用了两种思路去做:
1.贪心:
网上的大神的讲解:
我们从1月开始贪心,每次将亏损的月份放在最后面才可以得到最优的结果
因为如果我们并没有把亏损的月份放在最后面的话,有可能会出现下一次的亏损月份没有考虑这个亏损的月份导致考虑更多的情况出现,所以说我们的贪心思路就是从后往前贪心

2.DP:
我的思路是这样的,在5月之前,我们的弦乐处理一下,然后在之后的几个月利用DP递推公式O(n)求解,不需要贪心的回溯了,可以加快速度
每次利用前四个月推到第五个月
定义状态:
保证最优的情况下的每个月的收入或者亏损
状态转移方程:
if(sum(前4个月+本月盈利)>=0) dp[i]=-delse dp[i]=s

3.Code:

1.贪心:16ms
#include<iostream> #include"cstdio"using namespace std;   int add(int m[],int n) //从第n个月开始,5个月的盈亏总和  {   int sum=0;    for(int i=n;i<n+5;i++)  sum+=m[i];   return sum; }  int main() {   int s,d;   int month[12];   while(scanf("%d%d",&s,&d)!=EOF)   //这里不要随便用for(;;),除非有终止条件让他break掉     {              d=-d;              for(int i=0;i<12;i++) month[i]=s;                 for(int i=0;i<8;i++)       {          for(int j=1;j<=5;j++)  //这里要有=号,就是有可能一个月的盈利大于4个月的亏损情况,那只能是全亏了           {             int tmp = add(month,i);             if(tmp>=0) month[i+5-j]=d;            else break;          }       }               int sum=0;       for(int i=0;i<12;i++)  sum+=month[i];                     if(sum>0)  cout<<sum<<endl;       else cout<<"Deficit"<<endl;    }     return 0; } 
2.DP 0ms
#include"iostream"#include"cstdio"#include"cstring"#include"cstdlib"using namespace std;int dp[13];int s,d;int sum;int main(){while(scanf("%d%d",&s,&d)!=EOF){for(int i=1;i<=12;i++){if(i<=5){if((5-i)*(-d)+i*s>=0) {for(int j=i;j<=5;j++) dp[j]=-d;i=5; }else dp[i]=s;}else{if(dp[i-1]+dp[i-2]+dp[i-3]+dp[i-4]+s>=0) dp[i]=-d;else dp[i]=s;}}sum=0;for(int i=1;i<=12;i++) sum+=dp[i];if(sum<0) printf("Deficit\n");else printf("%d\n",sum);}return 0;}

4.问题抽象

假设现在有一个数组有n个元素,每个元素只有a,b两种选择,现在让每个数组元素的连续k个数字之和必小于0,求满足条件的序列中
序列和最大的一个,并输出序列的满足条件的情况
本问题我们可以利用DP(O(n)解决)
我们首先预处理前k个元素,利用贪心的思路O(k)求出满足第一个连续5个元素的情况
然后之后利用上面的思路不断地递推求出整个序列的所有的情况

1 0
原创粉丝点击