概述
好久没做过一道像样的区间DP了,做出来得慢了点,一开始还用个堆维护最优值然后超时了,菜哭.jpg
f[i][j]表示覆盖i段邮集,1到j号颜色最多能覆盖多少个,那么能转移到f[i][j]的必定是[x,y]包含j颜色的邮集,用一个单调队列来维护这些邮集能转移到f[i][j]的最优值。但是入队的时候是按照x的位置来入队,队首出队的时候表示已经对j这个位置没有影响了,则是根据y来队首出队,我们贪心地考虑到,如果一个区间被另外一个区间包含,那么它肯定不是最优的,把他标记为不选,那么单调队列入队是按照x从左到右的,队首出队的y也是从左到右的,那么就满足单调队列的性质了(不满足的话就不能用要用堆了)。
#include<bits/stdc++.h>
#define maxl 2010
using namespace std;
int n,cnt,m,k,cas,ans,top;
int f[maxl][maxl];
struct lne
{
int l,r;
bool operator <(const lne &b) const
{
if(l==b.l)
return r>b.r;
else
return l<b.l;
}
}a[maxl];
int head,tail;
struct node
{
int val,r;
}q[maxl];
bool in[maxl];
inline void prework()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
f[i][j]=0;
for(int i=1;i<=m;i++)
scanf("%d%d",&a[i].l,&a[i].r),in[i]=true;
sort(a+1,a+1+m);
int last=1;cnt=1;
for(int i=2;i<=m;i++)
if(a[i].r<=a[last].r)
in[i]=false;
else
last=i,cnt++;
k=min(k,cnt);
}
inline void mainwork()
{
ans=0;
int id;
for(int i=1;i<=k;i++)
{
head=1;tail=0;id=1;
for(int j=1;j<=n;j++)
{
while(a[id].l<=j && id<=m)
{
if(in[id])
{
int l=a[id].l,r=a[id].r,tmp=f[i-1][l-1]-l+1;
while(head<=tail && (tmp>q[tail].val || (tmp==q[tail].val && r>=q[tail].r)))
tail--;
q[++tail]=node{tmp,r};
}
id++;
}
while(head<=tail && q[head].r<j)
head++;
f[i][j]=max(f[i][j-1],f[i-1][j]);
if(head<=tail)
f[i][j]=max(f[i][j],q[head].val+j);
}
}
}
inline void print()
{
ans=0;
printf("Case #%d: %dn",cas,f[k][n]);
}
int main()
{
int t;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}
后来发现:
因为覆盖是连续的,那么覆盖得肯定越远越好,我们用t[j]表示所有覆盖过j位置的邮集y最远的地方是哪里,那么直接由f[i-1][j-1]转移到f[i][t[j]]就行了,然后f[i][j]=max(f[i][j],f[i-1][j],f[i][j-1])
#include<bits/stdc++.h>
#define maxl 2010
using namespace std;
int n,m,k,cas;
int t[maxl];
int f[maxl][maxl];
inline void prework()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
f[i][j]=0,t[j]=0;
int x,y;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
for(int j=x;j<=y;j++)
t[j]=max(t[j],y);
}
}
inline void mainwork()
{
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=max(f[i][j],max(f[i-1][j],f[i][j-1]));
if(t[j])
f[i][t[j]]=max(f[i-1][j-1]+t[j]-j+1,f[i][t[j]]);
}
}
}
inline void print()
{
printf("Case #%d: %dn",cas,f[k][n]);
}
int main()
{
int t;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}
最后
以上就是能干方盒为你收集整理的HDU6249的全部内容,希望文章能够帮你解决HDU6249所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复