在0~m的时间段里,有N个职员在公司工作,每个人在从 sti 出公司出差,在 eni 回公司,公司有个大门,有K把备用钥匙,门一开始锁着,在公司内部可以开锁上锁,出去了或者要进来时,只有带了备用钥匙的人才能开锁上锁,现在在保证每个人出入无忧的情况下,求上锁最长时间。
在每个单位时间里,至多有1个人经过大门。
N,K<=1000
初看这道题,可能不知道如何决策,只能乱搞。其实每个 sti 和 eni 分割出了很多个时间段,有四种情况
1,如果是两进,那么后一个人有钥匙前一个人进门后就可以锁门。
2,如果是左进右出,那么肯定可以锁门,钥匙都不用。
3,如果是两出,那么前一个人有钥匙就可以锁门。
4,如果是左出右进,只有两人都有钥匙前一个人才能锁门。
2就直接加进答案。
1、3两种情况我们可以设一个val[]来记录一个人拿了钥匙之后,对于1、4两种情况可取的时间段和,这个不会有后效性。
情况4是最关键的,如果没有3的话,前面的就可以一个dp搞定。
把每个人看成点,情况4就可以看作是一个点走到另一个点的无向边,从而获得这条边的价值,即这个时间段。
显然,只会出现链。
重新编号,同一条链的点排在一起,只取一个点x,获得val[x](编号后重新构造的val[]),连续取x+1、x(同一条链)就可以获得额外价值。
这样,转化成了dp,再加上一个简单优化,过了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int N=5005;
struct rec
{
int val,inv;
}b[N*5];
int n,m,k,j,s[N],t[N],f[2005][2005][2],ans,dur,p,i,t1,pd[N],a[N],pp,ex[N],val[N],rd[N],next[N],co[N],first[N],d[N],tt;
bool cmp(rec a,rec b)
{
return a.val<b.val;
}
int cr(int x,int y,int z)
{
rd[++tt]=y;
next[tt]=first[x];
co[tt]=z;
first[x]=tt;
d[y]++;
}
int dfs(int x,int y)
{
pd[x]=1;
a[++tt]=x;
for(int p=first[x];p;p=next[p])
if (rd[p]!=y)
{
ex[rd[p]]=co[p];
dfs(rd[p],x);
}
}
int main()
{
freopen("key.in","r",stdin);
freopen("key.out","w",stdout);
scanf("%d%d%d",&n,&m,&p);
fo(i,1,n)
{
scanf("%d%d\n",&s[i],&t[i]);
b[i*2-1]={s[i],i};
b[i*2]={t[i],i+n};
}
sort(b+1,b+1+2*n,cmp);
ans=b[1].val+m-b[2*n].val;
fo(i,1,2*n-1)
{
dur=b[i+1].val-b[i].val;
if ((b[i].inv<=n&&b[i+1].inv<=n)||b[i].inv==b[i+1].inv-n) val[b[i].inv]+=dur;else
if (b[i].inv>n&&b[i+1].inv<=n) ans+=dur;else
if (b[i].inv<=n&&b[i+1].inv>n)
{
cr(b[i].inv,b[i+1].inv-n,dur);
cr(b[i+1].inv-n,b[i].inv,dur);
}else
if (b[i].inv>n&&b[i+1].inv>n) val[b[i+1].inv-n]+=dur;
}
tt=0;
fo(i,1,n)
if ((!pd[i])&&d[i]<2)
dfs(i,0);
fo(i,0,n) fo(j,0,k) f[i][j][0]=f[i][j][1]=-(1<<30);
f[0][0][0]=0;
fo(i,1,n)
{
f[i][0][0]=0;
fo(j,1,min(i,p))
{
f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
f[i][j][1]=max(f[i-1][j-1][0],f[i-1][j-1][1]+ex[a[i]])+val[a[i]];
}
}
printf("%d",max(f[n][min(n,p)][0],f[n][min(n,p)][1])+ans);
}
这道题打起来很简单,思考上,问题的两个转化需要耐心和技巧。通过这道题可以发现,草稿纸上画个图是件好事!