zoukankan      html  css  js  c++  java
  • COGS743. [网络流24题] 最长k可重区间集

    743. [网络流24题] 最长k可重区间集

    ★★★   输入文件:interv.in   输出文件:interv.out   简单对比
    时间限制:1 s   内存限制:128 MB

    «问题描述:


    «编程任务:
    对于给定的开区间集合I和正整数k,计算开区间集合I的最长k可重区间集的长度。
    «数据输入:
    由文件interv.in提供输入数据。文件的第1 行有2 个正整数n和k,分别表示开区间的
    个数和开区间的可重迭数。接下来的n行,每行有2个整数,表示开区间的左右端点坐标。
    «结果输出:
    程序运行结束时,将计算出的最长k可重区间集的长度输出到文件interv.out中。
    输入文件示例 输出文件示例
    interv.in
    4 2
    1 7
    6 8
    7 10

    9 13

    interv.out

    15

    这样的区间建图比较好想,因为以前做过用最短路的最小区间覆盖问题,想法类似

    BYVOID:

    离散化所有区间的端点,把每个端点看做一个顶点,建立附加源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,费用为区间长度的有向边。

    两点:

    1.相邻的连一条边,避免了每个点都和s t连边

    2.容量限制为k,经过每个点的边数一定<=k

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int N=1005,M=1e5+5,INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        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;
    }
    int n,k,mp[N],m,l[N],r[N],s,t;
    int Bin(int v){
        int l=1,r=m;
        while(l<=r){
            int mid=(l+r)>>1;
            if(mp[mid]==v) return mid;
            if(v<mp[mid]) r=mid-1;
            else l=mid+1;
        }
        return -1;
    }
    struct edge{
        int v,ne,c,f,w;
    }e[M<<1];
    int cnt,h[N];
    inline void ins(int u,int v,int c,int w){
        //printf("ins %d %d %d %d  %d %d
    ",u,v,c,w,mp[u],mp[v]);
        cnt++;
        e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].w=w;
        e[cnt].ne=h[u];h[u]=cnt;
        cnt++;
        e[cnt].v=u;e[cnt].c=0;e[cnt].f=0;e[cnt].w=-w;
        e[cnt].ne=h[v];h[v]=cnt;
    }
    void build(){
        s=0;t=m+1;
        ins(s,1,k,0);ins(m,t,k,0);
        for(int i=1;i<m;i++)
            ins(i,i+1,INF,0);
        for(int i=1;i<=n;i++)
            ins(Bin(l[i]),Bin(r[i]),1,-(r[i]-l[i]));
    }
    int q[N],head,tail,d[N],inq[N],pre[N],pos[N];
    inline void lop(int &x){if(x==N) x=1;else if(x==0) x=N-1;}
    bool spfa(){
        memset(d,127,sizeof(d));
        memset(inq,0,sizeof(inq));
        head=tail=1;
        q[tail++]=s;inq[s]=1;d[s]=0;
        pre[t]=-1;
        while(head!=tail){
            int u=q[head++];inq[u]=0;lop(head);
            for(int i=h[u];i;i=e[i].ne){
                int v=e[i].v,w=e[i].w;
                if(e[i].c>e[i].f&&d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    pos[v]=i;pre[v]=u;
                    if(!inq[v]){
                        inq[v]=1;
                        if(d[v]<d[q[head]]) head--,lop(head),q[head]=v;
                        else q[tail++]=v,lop(tail);
                    }
                }
            }
        }
        return pre[t]!=-1;
    }
    int mcmf(){
        int flow=0,cost=0;
        while(spfa()){
            int f=INF;
            for(int i=t;i!=s;i=pre[i]) f=min(f,e[pos[i]].c-e[pos[i]].f);
            flow+=f;cost+=-d[t]*f;//printf("flow %d
    ",flow);
            for(int i=t;i!=s;i=pre[i]){
                int p=pos[i];
                e[p].f+=f;
                e[((p-1)^1)+1].f-=f;
            }
        }
        return cost;
    }
    int main(){
        freopen("interv.in","r",stdin);
        freopen("interv.out","w",stdout);
        n=read();k=read();
        for(int i=1;i<=n;i++) mp[++m]=l[i]=read(),mp[++m]=r[i]=read();
        sort(mp+1,mp+1+m);
        int p=0;mp[++p]=mp[1];
        for(int i=2;i<=m;i++) if(mp[i]!=mp[i-1]) mp[++p]=mp[i];
        m=p;
        build();
        printf("%d
    ",mcmf());
    }
  • 相关阅读:
    好用的Win7下硬盘分区软件:Acronis Disk Director Suite
    SQL Server 相关create操作语句
    我也有博客了
    N层构架如何实现
    SQL相关增删改查语句
    1.MVC的工作流程
    回顾去年以来读过的书
    [Architecture]Facebook Chat
    [Tips]解决make_sock: could not bind to address 0.0.0.0:XXXX
    Emacs中的按键组合
  • 原文地址:https://www.cnblogs.com/candy99/p/6185232.html
Copyright © 2011-2022 走看看