[网络流 24 题]最长k可重区间集(费用流)

Posted Zars19

tags:

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

Description

给定实直线L 上n 个开区间组成的集合I,和一个正整数k,试设计一个算法,从开区间集合I 中选取出开区间集合S属于I,使得在实直线L 的任何一点x,S 中包含点x 的开区间个数不超过k,且sum(|z|)z属于S,达到最大。这样的集合S称为开区间集合I的最长k可重区间集。sum(|z|) z属于S称为最长k可重区间集的长度。对于给定的开区间集合I和正整数k,计算开区间集合I的最长k可重区间集的长度。

Solution

1.离散化 然后从每个点i向i+1连一条流量为INF,费用为0的边

2.对于每个区间,从l[i]到r[i]连一条流量为1,费用为长度的边

3.分别从s向第一个点、最后一个点到t连流量为k,费用为0的边

跑最大费用最大流~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int s,t,n,k,head[1005],cnt=0,a[505],b[505],c[1005],tot=0;
int dis[1005],f[1005],pre[1005];
bool inq[1005];
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}
struct Node
{
    int next,from,to,cap,w;
}Edges[500005];
void addedge(int u,int v,int c,int w)
{
    Edges[cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt].from=u,Edges[cnt].to=v;
    Edges[cnt].w=w;
    Edges[cnt++].cap=c;
}
void insert(int u,int v,int c,int w)
{
    addedge(u,v,c,w);
    addedge(v,u,0,-w);
}
queue<int>q;
int MCMF()
{
    int flow=0,cost=0;
    while(1)
    {
        memset(dis,-1,sizeof(dis));
        memset(f,0,sizeof(f));
        q.push(s),pre[s]=-1,inq[s]=1,dis[s]=0,f[s]=INF;
        while(!q.empty())
        {
            int u=q.front();
            q.pop(),inq[u]=0;
            for(int i=head[u];~i;i=Edges[i].next)
            {
                int v=Edges[i].to;
                if(Edges[i].cap>0&&dis[v]<dis[u]+Edges[i].w)
                {
                    dis[v]=dis[u]+Edges[i].w;
                    f[v]=min(f[u],Edges[i].cap);
                    pre[v]=i;
                    if(!inq[v])q.push(v),inq[v]=1;
                }
            }    
        }
        if(!f[t])break;
        flow+=f[t],cost+=dis[t]*f[t];
        int p=t;
        while(pre[p]!=-1)
        {
            Edges[pre[p]].cap-=f[t];
            Edges[pre[p]^1].cap+=f[t];
            p=Edges[pre[p]].from;
        }
    }
    return cost;
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read(),k=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read(),b[i]=read();
        if(a[i]>b[i])swap(a[i],b[i]);
        c[++tot]=a[i],c[++tot]=b[i];
    }
    sort(c+1,c+1+tot);
    tot=unique(c+1,c+1+tot)-c-1;
    for(int i=1;i<=n;i++)
    {
        int len=b[i]-a[i];
        a[i]=lower_bound(c+1,c+1+tot,a[i])-c;
        b[i]=lower_bound(c+1,c+1+tot,b[i])-c;
        insert(a[i],b[i],1,len);
    }
    s=0,t=tot+1;
    insert(s,1,k,0),insert(tot,t,k,0);
    for(int i=1;i<tot;i++)
    insert(i,i+1,INF,0);
    printf("%d\n",MCMF());
    return 0;
}

 

以上是关于[网络流 24 题]最长k可重区间集(费用流)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

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

luogu P3358 最长k可重区间集问题