最长k可重区间集问题

Posted tply

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长k可重区间集问题相关的知识,希望对你有一定的参考价值。

最长k可重区间集问题

题目链接 https://www.luogu.org/problemnew/show/3358

做法

所有点向下一个点连容量为k费用为0的边
l和r连容量为1费用为区间长度的边
然后跑最大流最大费用流
(最大费用就是把边权取相反数跑最小费用
最后再输出最终费用的相反数)

思考

在整张图中,只有l - >r的边有费用
而且费用为区间长度
(i->i+1费用为0)
所以跑最大费用也就是求最长区间

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #define ul unsigned long long
    #define rg register int
    #define ll long long
    #define il inline
    #define INF 2147483647
    #define SZ 10000000
    using namespace std;
    int n,N,k,s,t,a[SZ],l[SZ],r[SZ];
/* N : 原数组大小

n : 离散化之后的数组大小

a[] : 离散数组

k : 可重迭数

l , r 所给区间左端点和右端点

*/

    struct Edge{int to,nxt,w,c;}e[SZ];
    int Ehead[SZ],pv[SZ],pe[SZ],Ecnt=2;
    il void Eadd(int u,int v,int w,int cost)
    {
        e[Ecnt]=(Edge){v,Ehead[u],w,cost};
        Ehead[u]=Ecnt++;
        e[Ecnt]=(Edge){u,Ehead[v],0,-cost};
        Ehead[v]=Ecnt++;
    }
/* 加边函数

pv[i] : spfa时使得i点dis值松弛的节点

(最短路的上一节点)

pe[i] : i与pv[i]连接的边

e[i].w : 流量

e[i].c : 费用

*/

    // 费用流板子 ‘_‘↓↓↓
    ll dis[SZ];
    int vis[SZ];
    queue <int> Q;
    bool spfa()
    {
        memset(dis,63,sizeof(dis));
        dis[s]=0; Q.push(s);
        while(!Q.empty())
        {
            rg u=Q.front();
            Q.pop();
            for(rg i=Ehead[u];i;i=e[i].nxt)
            {
                rg v=e[i].to;
                if((e[i].w)&&(dis[v]>dis[u]+e[i].c))
                {
                    dis[v]=dis[u]+e[i].c;
                    pe[v]=i;
                    pv[v]=u;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        Q.push(v);
                    }
                }
            }
            vis[u]=0;
        }    
        return dis[t]<dis[0];
    }
    il void costflow()
    {
        ll Ans=0;
        while(spfa())
        {
            rg di=INF;
            for(rg i=t;i!=s;i=pv[i])
             di=min(di,e[pe[i]].w);
            for(rg i=t;i!=s;i=pv[i])
            {
                e[pe[i]].w-=di;
                e[pe[i]^1].w+=di;
                Ans+=1ll*di*e[pe[i]].c;
            }
        }
        printf("%lld",-Ans);
    }
    // 费用流板子 ‘_‘↑↑↑
    int main()
    {
        scanf("%d%d",&N,&k);
        for(rg i=1;i<=N;++i)
        {
            scanf("%d%d",&l[i],&r[i]);
            if(l[i]>r[i]) swap(l[i],r[i]);
            a[i]=l[i];a[i+N]=r[i];
        }
        sort(a+1,a+N+N+1);
        n=unique(a+1,a+N+N+1)-a-1;
        for(rg i=1;i<=N;++i)
        {
            rg L=lower_bound(a+1,a+n+1,l[i])-a;
            rg R=lower_bound(a+1,a+n+1,r[i])-a;
            Eadd(L,R,1,l[i]-r[i]);
        }
/* 利用unique和lower_bound离散化

原理是把输入到l[i]与r[i]出现的所有数字

排完序后利用unique去重

注意那些+1-1什么的

*/

        for(rg i=1;i<n;++i)
         Eadd(i,i+1,INF,0);
        s=n+1;t=n+2;
        Eadd(s,1,k,0);
        Eadd(n,t,k,0);
        costflow();
        while(1);
        return 0;
}

以上是关于最长k可重区间集问题的主要内容,如果未能解决你的问题,请参考以下文章

网络流 P3358 最长k可重区间集问题

最长k可重区间集问题

最长k可重区间集(cogs 743)

P3358 最长k可重区间集问题

网络流24题21最长k可重区间集问题

「网络流24题」「LuoguP3358」 最长k可重区间集问题