最长可重区间集

一直没有思路啊。。
看了下byvoid的解释,强啊
以下内容来自byvoid https://www.byvoid.com/zhs/blog/lpf24-solution

最大权不相交路径问题,可以用最大费用最大流解决。

【建模方法】

方法1

按左端点排序所有区间,把每个区间拆分看做两个顶点<i.a><i.b>,建立附加源S汇T,以及附加顶点S'。

1、连接S到S'一条容量为K,费用为0的有向边。
2、从S'到每个<i.a>连接一条容量为1,费用为0的有向边。
3、从每个<i.b>到T连接一条容量为1,费用为0的有向边。
4、从每个顶点<i.a>到<i.b>连接一条容量为1,费用为区间长度的有向边。
5、对于每个区间i,与它右边的不相交的所有区间j各连一条容量为1,费用为0的有向边。

求最大费用最大流,最大费用流值就是最长k可重区间集的长度。

方法2

离散化所有区间的端点,把每个端点看做一个顶点,建立附加源S汇T。

1、从S到顶点1(最左边顶点)连接一条容量为K,费用为0的有向边。
2、从顶点2N(最右边顶点)到T连接一条容量为K,费用为0的有向边。
3、从顶点i到顶点i+1(i+1<=2N),连接一条容量为无穷大,费用为0的有向边。
4、对于每个区间[a,b],从a对应的顶点i到b对应的顶点j连接一条容量为1,费用为区间长度的有向边。

求最大费用最大流,最大费用流值就是最长k可重区间集的长度。

【建模分析】

这个问题可以看做是求K条权之和最大的不想交路径,每条路径为一些不相交的区间序列。由于是最大费用流,两条路径之间一定有一些区间相交,可以看做事相交部分重复了2次,而K条路经就是最多重复了K次。最简单的想法就是把区间排序后,不相交的区间之间连接一条边,由于每个区间只能用一次,所以要拆点,点内限制流量。如果我们改变一下思路,把端点作为网络中的顶点,区间恰恰是特定一些端点之间的边,这样建模的复杂度更小。方法1的边数是O(N^2)的,而方法2的边数是O(N)的,可以解决更大规模的问题。

建模很吼啊。。。。我真的naïve

#include <queue>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=505<<2,S=0,S1=N-1,T=N-2,inf=0x3f3f3f3f;
int n,k;
struct Seg {
    int l,r;
} seg[505];
int ecnt=1,head[N],dis[N],from[N],mincost,maxflow;
bool inq[N];
struct Edge {
    int to,nxt,val,cost,from;
} e[505*505+505*2];
void add(int bg,int ed,int val,int cost) {
    e[++ecnt].cost=cost;
    e[ecnt].from=bg;
    e[ecnt].nxt=head[bg];
    e[ecnt].to=ed;
    e[ecnt].val=val;
    head[bg]=ecnt;
}
void insert(int bg,int ed,int val,int cost) {
    cost=-cost;
    add(bg,ed,val,cost);
    add(ed,bg,0,-cost);
}
queue<int>qu;
bool spfa() {
    qu.push(S);
    std::memset(dis,0x3f,sizeof dis);
    dis[S]=0;
    inq[S]=1;
    while(!qu.empty()) {
        int u=qu.front();
        qu.pop();
        inq[u]=0;
        for(int i=head[u],v; i; i=e[i].nxt) {
            v=e[i].to;
            if(dis[v]>dis[u]+e[i].cost&&e[i].val) {
                dis[v]=dis[u]+e[i].cost;
                from[v]=i;
                if(!inq[v]) qu.push(v),inq[v]=1;
            }
        }
    }
    return dis[T]!=inf;
}
void min(int &x,int y) {
    x=x<y?x:y;
}
void mcf() {
    int x=inf,i=from[T];
    while(i) {
        min(x,e[i].val);
        i=from[e[i].from];
    }
    maxflow+=x;
    i=from[T];
    while(i) {
        e[i].val-=x;
        e[i^1].val+=x;
        mincost-=x*e[i].cost;
        i=from[e[i].from];
    }
}
bool cmp(Seg x,Seg y) {
    return x.l<y.l;
}
int main() {
    scanf("%d%d",&n,&k);
    for(int i=1; i<=n; i++) scanf("%d%d",&seg[i].l,&seg[i].r);
    sort(seg+1,seg+1+n,cmp);
    insert(S,S1,k,0);
    for(int i=1; i<=n; i++) insert(S1,i,1,0),insert(i+n,T,1,0),insert(i,i+n,1,seg[i].r-seg[i].l);
    for(int i=1; i<=n; i++)
        for(int j=i+1; j<=n; j++)
            if(seg[i].r<=seg[j].l) insert(i+n,j,1,0);
    while(spfa())mcf();
    printf("%d",mincost);
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9280937.html