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

P4890 Never·island(dp)

时间:2019-04-08 21:37:53      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:dfs   数组   http   class   起点   选择   code   har   sizeof   

P4890 Never·island

求门开的最小时间,其实也就是求门关的最大时间。

坐标这么大....显然坐标要离散化

离散化排序后,我们发现x轴被这些点划分成若干条线段$(l,r)$,并且有4种情况

我们用$v[i]$数组表示给队$i$钥匙的贡献

1.左端点为$i$队的起点,右端点为$i$队的终点:显然队$i$钥匙的贡献包括这一段,$v[i]+=r-l$

2.左端点为$i$队的终点,右端点为$j$队的起点:无论如何分配钥匙,这一段都可以关门,于是答案可直接算上$r-l$

3.左端点为$i$队的终点,右端点为$j$队的终点:如果我们给$j$队钥匙,$i$队就可以关门,$v[j]+=r-l$

4.左端点为$i$队的起点,右端点为$j$队的终点:我们只有给$i,j$各一把钥匙,才能算上这一段的贡献

于是我们就在$i,j$之间先连边,边权为$r-l$

蓝后我们又发现,这些点由一些互不相干的链组成。

于是我们按$x轴$从左到右dfs一遍求出dp的优先顺序

最后我们用$f[i][j][0/1]$表示前$i$个点,已给$j$个点钥匙,是否选择了第$i$个(当前)点的最优解

这就是一个二维dp辣

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define rint register int
using namespace std;
inline int Max(int a,int b){return a>b?a:b;}
inline int Min(int a,int b){return a<b?a:b;}
void read(int &x){
    char c=getchar();x=0;
    while(c<0||c>9) c=getchar();
    while(0<=c&&c<=9) x=x*10+(c^48),c=getchar();
}
#define N 4005
int n,m,pos[N],tp,h[N],nxt[N],v[N],sv[N];
int f[N][N][2],tot; bool vis[N];
map <int,int> mp;
void dfs(int x){vis[h[++tp]=x]=1; if(nxt[x])dfs(nxt[x]);}
int main(){
    read(n);read(m); int l,r,L,R,tn=n<<1;
    for(rint i=1;i<=n;++i){
        read(l), read(r);
        pos[i]=l, pos[i+n]=r;
        mp[l]=i<<1, mp[r]=i<<1|1;
    }sort(pos+1,pos+tn+1);//离散化
    for(rint i=1;i<tn;++i){
        l=pos[i], r=pos[i+1];
        L=mp[l], R=mp[r];
        if((L&1)&&(R&1)) v[R>>1]+=r-l;
        if((L&1)&&!(R&1)) tot+=r-l;
        if(!(L&1)&&!(R&1)) v[L>>1]+=r-l;
        if(!(L&1)&&(R&1)){
            if((L>>1)==(R>>1)) v[L>>1]+=r-l;
            else nxt[R>>1]=L>>1,sv[R>>1]=r-l;
        }
    }
    for(rint i=1;i<=tn;++i){
        int p=mp[pos[i]];
        if(!(p&1)&&!vis[p>>1]) dfs(p>>1);
    }//dfs确定dp顺序
    memset(f,0xbf,sizeof(f));//-inf
    f[n+1][0][0]=0;
    for(rint i=n;i;--i){
        f[i][0][0]=0;
        for(rint j=Min(n-i+1,m);j;--j){
            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]+sv[h[i]])+v[h[i]];
        }
    }printf("%d",pos[tn]-pos[1]-tot-Max(f[1][m][1],f[1][m][0]));
    return 0;
}

 

P4890 Never·island(dp)

标签:dfs   数组   http   class   起点   选择   code   har   sizeof   

原文地址:https://www.cnblogs.com/kafuuchino/p/10673322.html

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