poj 3245 Sequence Partitioning dp+二分+单调队列

 

poj 3245 Sequence Partitioning dp+二分+单调队列

分类: 动态规划   116人阅读  评论(0)  收藏  举报

题目链接:

http://poj.org/problem?id=3245

题目大意:

有n个连续的数对(Ai,Bi).求一个划分,使得每一部分的B的和的最大值最小。

划分要求:

1、对于任意的p<q , p,q属于不同的部分,则有Bp>Aq.

2、对于每一部分的最大A的和小于给定的lim.

解题思路:

当p<q是如果Bp<=Aq则p,q一定是属于一个部分。

先把必须在一起的粗略划分下,然后二分B的和的最小值。

dp[i]表示到达第i个数对时,此时的最大的A的和。

dp[i]=min{dp[j]+max(Ak,j+1<=k<=i),其中b(j+1)+...+b(i)<=二分的值。

代码:

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cmath>  
  3. #include<cstdio>  
  4. #include<cstdlib>  
  5. #include<string>  
  6. #include<cstring>  
  7. #include<algorithm>  
  8. #include<vector>  
  9. #include<map>  
  10. #include<set>  
  11. #include<stack>  
  12. #include<list>  
  13. #include<queue>  
  14. #define eps 1e-6  
  15. #define INF 0x1f1f1f1f  
  16. #define PI acos(-1.0)  
  17. #define ll __int64  
  18. #define lson l,m,(rt<<1)  
  19. #define rson m+1,r,(rt<<1)|1  
  20. using namespace std;  
  21.   
  22. /* 
  23. freopen("data.in","r",stdin); 
  24. freopen("data.out","w",stdout); 
  25. */  
  26. #define M 55000  
  27. int n,lim,a[M],b[M],p[M],q[M]; //p[i]表示将b数组从小到大排序后的下标,  
  28. //q[i]表示b中的第i号元素与a中的q[i]号元素可能有冲突  
  29. int dp[M]; //dp[i]表示到达第i个数对时,a中能达到的最小值  
  30.   
  31. bool cmp(int i,int j)  
  32. {  
  33.    return b[i]<b[j];  //按b数组排序,将下标对应交换  
  34. }  
  35.   
  36. multiset<int>sbt; //多重集合容器,里面的存储结构是平衡二叉树  
  37. bool iscan(int m)  
  38. {  
  39.    int p=1,r=-1,le=0;  
  40.    ll sum=0;  
  41.    sbt.clear();  
  42.   
  43.    for(int i=1;i<=n;i++)  
  44.    {  
  45.       sum+=b[i];  
  46.       while(sum>m)  
  47.          sum-=b[p++];  
  48.       if(p>i)  
  49.          return false//说明有单个的值超过了m  
  50.       while(le<=r&&a[i]>=a[q[r]]) //去掉后面的小的  
  51.       {  
  52.          if(le<r)  
  53.             sbt.erase(dp[q[r-1]]+a[q[r]]);  //注意使得A的最大值和最小时,  
  54.                                           //可以以最大的a[i]为分界点  
  55.          r--;  
  56.       }  
  57.       q[++r]=i;  
  58.       if(le<r) //如果队列至少有两个元素  
  59.          sbt.insert(dp[q[r-1]]+a[q[r]]);  
  60.       while(le<=r&&q[le]<p)  
  61.       {  
  62.          if(le<r)  
  63.             sbt.erase(dp[q[le]]+a[q[le+1]]);  
  64.          le++;  
  65.       }  
  66.       dp[i]=a[q[le]]+dp[p-1];  
  67.       ll tmp=*sbt.begin();  
  68.       if(le<r&&tmp<dp[i]) //队列中至少有两个元素  
  69.          dp[i]=tmp;  
  70.    }  
  71.    return dp[n]<=lim;  
  72. }  
  73.   
  74. int main()  
  75. {  
  76.    while(scanf("%d%d",&n,&lim)!=EOF)  
  77.    {  
  78.       for(int i=1;i<=n;i++)  
  79.       {  
  80.          scanf("%d%d",&a[i],&b[i]);  
  81.          q[i]=p[i]=i;  
  82.       }  
  83.       sort(p+1,p+n+1,cmp);  
  84.       for(int i=n,j=1;i>=1;i--)  
  85.          while(j<=n&&b[p[j]]<=a[i]) //将b中与a冲突的标记  
  86.                q[p[j++]]=i;         //将b全部用完,尽量去消耗下标值大的,  
  87.                                     //小的不用管了,找到最大冲突区间  
  88.   
  89.       int le,ri,j=1;  
  90.       for(int i=1;i<=n;i=le,j++)  //有冲突一定要放在一起  
  91.       {  
  92.          a[j]=a[i],b[j]=b[i];  
  93.          for(le=i+1,ri=max(q[i],i);le<=ri;le++)  
  94.          {  
  95.             a[j]=max(a[j],a[le]);  
  96.             b[j]+=b[le];  
  97.             ri=max(ri,q[le]); //又产生了新的冲突  
  98.          }  
  99.       }  
  100.       n=j-1;//现在一共只有j-1组了  
  101.       le=1,ri=((1<<31)-1);  
  102.       //printf("%d\n",ri);  
  103.       int m,ans;  
  104.   
  105.       while(le<=ri)  
  106.       {  
  107.          m=(le+ri)>>1;  
  108.          if(iscan(m))  
  109.             ans=m,ri=m-1; //能否更小  
  110.          else  
  111.             le=m+1;//不行的话,增大  
  112.       }  
  113.       printf("%d\n",ans);  
  114.    }  
  115.    return 0;  
  116. }  
weixin028基于微信小程序小说阅读器设计+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值