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


    挺有意思的一道题,嘛,还是那句话,不要被固有思维给限制了

    嘛,我一开始找点来逐步分析,而后才看了题解发现时找边的关系,我很容易找题目不关紧要的条件啊.....

    首先这个题有两种建图方法

    第一种,直接把minl----maxl串起来,流量无穷大,费用为0,然后对于一个区间,Li,Ri

    从Li---Ri连一条边,流量1,费用Ri-Li,

    你建完图会发现,只有当两端区间相交时,才互相影响,所以,很好的处理除了区间只有k个....

    但....

    嘛,很不理想,

    那我们可以再在上面改进一下

    #include<bits/stdc++.h>
    using namespace std;
    
    int k,n,tot=-1,h[40005],inf=999999,maxl=0,minl=999999;
    
    struct node{
        int from,to,cost,next,rest;
    }e[1000005];
    int dis[40005],vis[40005],flow[40005],g[40005],ans=0,ans2=0;
    void bfs(int s,int t){
        memset(dis,0x7f,sizeof(dis));
        memset(vis,false,sizeof(vis));
        memset(flow,0x7f,sizeof(flow));
        memset(g,-1,sizeof(g));
        queue<int>q;q.push(s);vis[s]=true;dis[s]=0;
        while(!q.empty()){
            int u=q.front();q.pop();vis[u]=false;
            for(int i=h[u];i!=(-1);i=e[i].next){
                if(e[i].rest>0&&dis[e[i].to]>dis[u]+e[i].cost){
                    dis[e[i].to]=dis[u]+e[i].cost;
                    g[e[i].to]=i;
                    flow[e[i].to]=min(e[i].rest,flow[u]);
                    if(vis[e[i].to]==false){
                        vis[e[i].to]=true;
                        q.push(e[i].to);
                    }
                }
            }
        }
    }
    
    int EK(int s,int t){
        while(1){
            bfs(s,t);
            if(g[t]==(-1))break;
            ans+=flow[t],ans2+=flow[t]*dis[t];
            for(int p=t;p!=s;p=e[g[p]].from){
                e[g[p]].rest-=flow[t];
                e[g[p]^1].rest+=flow[t];
            }
        }
    }
        
    void add(int x,int y,int z,int hg){
        tot++;
        e[tot].next=h[x];
        h[x]=tot;
        e[tot].cost=hg;
        e[tot].from=x;
        e[tot].to=y;
        e[tot].rest=z;
    }
        
    void adde(int x,int y,int z,int hg){
        add(x,y,z,hg);
        add(y,x,0,-hg);
    }
    
    void init(){
        tot=(-1);
        ans=0,ans2=0;
        memset(h,-1,sizeof(h));
    }
    
    struct node2{
        int l,r;
    }ok[1005];
    
    bool cmp(node2 a,node2 b){
        return a.l<b.r;
    }
    
    int main(){
        init();
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            cin>>ok[i].l>>ok[i].r;
            maxl=max(maxl,ok[i].r);
            minl=min(minl,ok[i].l);
        }
        sort(ok+1,ok+1+n,cmp);
        for(int i=1;i<=n;i++){
            adde(ok[i].l,ok[i].r,1,-(ok[i].r-ok[i].l));
        }
        for(int i=minl;i<maxl;i++){
            adde(i,i+1,inf,0);
        }
        adde(0,minl,k,0);
        adde(maxl,20000,k,0);
        EK(0,20000);
        cout<<-ans2<<endl;
    }
    View Code

    于是就有了第二种方法,不需要把区间串起来,

    通过对上面的解析,只有当两端区间相交时,并且需要的只是费用

    很显然,假设我们不需要把整个区间建出来,只要处理出相交关系就ok了

    于是就有了步骤

    先将区间排序(按左端点)

    将每一个区间拆成两个点

    当有区间与这个区间不相交时,

    将上端点与那个端点下端点连起来

    同样很好的处理了区间内选k个的这种操作

    正确性显然把,假设后面有出现新的可以分配的区间,那么前面跟他不想交的直接连上...

    #include<bits/stdc++.h>
    using namespace std;
    
    int k,n,tot=-1,h[40005],inf=999999;
    
    struct node{
        int from,to,cost,next,rest;
    }e[1000005];
    int dis[40005],vis[40005],flow[40005],g[40005],ans=0,ans2=0;
    void bfs(int s,int t){
        memset(dis,0x7f,sizeof(dis));
        memset(vis,false,sizeof(vis));
        memset(flow,0x7f,sizeof(flow));
        memset(g,-1,sizeof(g));
        queue<int>q;q.push(s);vis[s]=true;dis[s]=0;
        while(!q.empty()){
            int u=q.front();q.pop();vis[u]=false;
            for(int i=h[u];i!=(-1);i=e[i].next){
                if(e[i].rest>0&&dis[e[i].to]>dis[u]+e[i].cost){
                    dis[e[i].to]=dis[u]+e[i].cost;
                    g[e[i].to]=i;
                    flow[e[i].to]=min(e[i].rest,flow[u]);
                    if(vis[e[i].to]==false){
                        vis[e[i].to]=true;
                        q.push(e[i].to);
                    }
                }
            }
        }
    }
    
    int EK(int s,int t){
        while(1){
            bfs(s,t);
            if(g[t]==(-1))break;
            ans+=flow[t],ans2+=flow[t]*dis[t];
            for(int p=t;p!=s;p=e[g[p]].from){
                e[g[p]].rest-=flow[t];
                e[g[p]^1].rest+=flow[t];
            }
        }
    }
        
    void add(int x,int y,int z,int hg){
        tot++;
        e[tot].next=h[x];
        h[x]=tot;
        e[tot].cost=hg;
        e[tot].from=x;
        e[tot].to=y;
        e[tot].rest=z;
    }
        
    void adde(int x,int y,int z,int hg){
        add(x,y,z,hg);
        add(y,x,0,-hg);
    }
    
    void init(){
        tot=(-1);
        ans=0,ans2=0;
        memset(h,-1,sizeof(h));
    }
    
    struct node2{
        int l,r;
    }ok[1005];
    
    bool cmp(node2 a,node2 b){
        return a.l<b.l;
    }
    
    int main(){
        init();
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            cin>>ok[i].l>>ok[i].r;
        }
        sort(ok+1,ok+1+n,cmp);
        adde(0,5000,k,0);
        for(int i=1;i<=n;i++){
            adde(5000,i,1,0);
            adde(i,i+n,1,-(ok[i].r-ok[i].l));
            adde(i+n,9999,1,0);
            for(int j=i+1;j<=n;j++){
                if(ok[i].r<=ok[j].l){
                    adde(i+n,j,1,0);
                }
            }
        }
        EK(0,9999);
        cout<<-ans2<<endl;
    }
    View Code
  • 相关阅读:
    类的加载过程
    ASCII码表
    uboot main_loop函数分析
    串行CPU设计
    __attribute__ ((section(".text")))的测试
    NandFlash
    测试gcc的优化选项
    如何编写一个简单的makefile
    UBOOT的多支持性与可裁剪性
    函数指针的使用
  • 原文地址:https://www.cnblogs.com/shatianming/p/12229590.html
Copyright © 2020-2023  润新知