ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-01-22 20:56:04  阅读:236  来源: 互联网

标签:24 可重 ok int flow tot vis 最长 dis


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

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

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

第一种,直接把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

标签:24,可重,ok,int,flow,tot,vis,最长,dis
来源: https://www.cnblogs.com/shatianming/p/12229590.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有