最长k可重区间集

Posted ~victorique~

tags:

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

 

 

P3358 最长k可重区间集问题

题目描述

技术分享图片

对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k可重区间集的长度。

输入输出格式

输入格式:

的第 1 行有 2 个正整数 n和 k,分别表示开区间的个数和开区间的可重迭数。接下来的 n行,每行有 2 个整数,表示开区间的左右端点坐标。

输出格式:

将计算出的最长 k可重区间集的长度输出

输入输出样例

输入样例#1:
4 2
1 7
6 8
7 10
9 13 
输出样例#1:
15

说明

对于100%的数据,1n500 ,1k3。

这个题貌似之前不停地打开然后放弃掉。。貌似主要原因是看不懂题面让我干些什么。。。上午的考试让我有了充足的时间观察题面,发现道理就是给了一堆区间,然后每个点不能被超过k个区间覆盖,每个区间的价值是它的长度,求最大价值。

然后一开始的时候一直都是想着怎么把互相覆盖这个条件把握好,然后各种如果他们有交集就连边之类的。。。后来发现并不可行,总是无法维护好。

然后看了题解豁然开朗,貌似自己的拆点连边什么的都没什么问题,甚至伪超级源这种东西都想到了,然而思路还是局限了我,这个题要向与自己没有交集的区间连边。然后去跑最大费用即可。。。真是可惜了。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#define ll long long
#define inf 50000000
#define re register
#define min(a,b) a<b?a:b
using namespace std;
struct po{
    int nxt,to,w,dis;
};
po edge[250001];
struct len{
    int l,r;
};
len a[1002];
int head[1050],num=-1,n,m,s,t,k,S;
int dis[1050],b[1050],tot;
inline int read()
{
    int x=0,c=1;
    char ch= ;
    while((ch>9||ch<0)&&ch!=-)ch=getchar();
    while(ch==-)c*=-1,ch=getchar();
    while(ch<=9&&ch>=0)x=x*10+ch-0,ch=getchar();
    return x*c;
}
inline void add_edge(int from,int to,int w,int dis)
{
    edge[++num].nxt=head[from];
    edge[num].to=to;
    edge[num].w=w;
    edge[num].dis=dis;
    head[from]=num;
}
inline void add(int from,int to,int w,int dis)
{
    add_edge(from,to,w,dis);
    add_edge(to,from,0,-dis);
}
inline bool spfa()
{
    memset(dis,50,sizeof(dis));
    memset(b,0,sizeof(b));
    deque<int> q;
    dis[t]=0;
    b[t]=1;
    q.push_back(t);
    while(!q.empty()){
        int u=q.front();
        q.pop_front();
        b[u]=0;
        for(re int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(edge[i^1].w>0&&dis[v]>dis[u]-edge[i].dis){
                dis[v]=dis[u]-edge[i].dis;
                if(!b[v]){
                    b[v]=1;
                    if(!q.empty()&&dis[v]<dis[q.front()])
                    q.push_front(v);
                    else
                    q.push_back(v);
                }
            }
        }
    }
    return dis[s]<inf;
}
inline int dfs(int u,int low)
{
    b[u]=1;
    if(u==t)
    return low;
    int diss=0;
    for(re int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(edge[i].w&&!b[v]&&dis[v]==dis[u]-edge[i].dis){
            int check=dfs(v,min(low,edge[i].w));
            if(check){
                tot+=edge[i].dis*check;
                low-=check;
                diss+=check;
                edge[i].w-=check;
                edge[i^1].w+=check;
                if(low==0) break;
            }
        }
    }
    return diss;
}
inline int max_flow(){
    int ans=0;
    while(spfa()){
        b[t]=1;
        while(b[t]){
            memset(b,0,sizeof(b));
            ans+=dfs(s,inf);
        }
    }
}
inline bool cmp(len x,len y)
{
    if(x.l<y.l) return 1;
    else if(x.l==y.l&&x.r<y.r) return 1;
    return 0;
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read();k=read();
    s=0;t=n+n+2;
    S=n+n+1;
    add(s,S,k,0);
    for(re int i=1;i<=n;i++){
        a[i].l=read();a[i].r=read();
        if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
    }
    sort(a+1,a+n+1,cmp);
    for(re int i=1;i<n;i++)
     for(re int j=i+1;j<=n;j++)
      if(a[i].r<=a[j].l) add(i+n,j,1,0);
    for(re int i=1;i<=n;i++){
        add(S,i,1,0);add(i+n,t,1,0);add(i,i+n,1,-a[i].r+a[i].l);
    }
    max_flow();
    cout<<-tot;
}

 

 

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

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

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

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

最长k可重区间集问题

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

P3358 最长k可重区间集问题