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

Posted qwerta

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「网络流24题」「LuoguP3358」 最长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%的数据,1<=n<=500,1<=k<=3

题解

建图:从$S$往$L$左端点连容量为k,费用为0;

从$L$上每个点$i$往点$i+1$连容量为INF,费用为0;

从$L$右端点往$T$连容量INF,费用为0。

>然后从每个区间的左端点往右端点连边,容量为1,费用为右端点$-$左端点(这道题区间长度的定义是右端点$-$左端点

然后跑最大费用最大流就行啦~

这样跑出来的费用会尽量大,而因为S处控制了流量,最大流就是k。

答案就是费用。

然后最大费用最大流就是把费用存负,跑最小费用最大流,输出答案的时候再取反就行了。

然后这道题长度没个范围,所以还要搞个离散。

  1 /*
  2     qwerta
  3     P3358 最长k可重区间集问题
  4     Accepted
  5     100
  6     代码 C++,2.16KB
  7     提交时间 2018-10-09 18:19:08
  8     耗时/内存
  9     31ms, 936KB
 10 */
 11 #include<algorithm>
 12 #include<iostream>
 13 #include<cstring>
 14 #include<cstdio>
 15 #include<cmath>
 16 #include<queue>
 17 using namespace std;
 18 const int INF=2e9;
 19 struct emm{
 20     int e,f,v,c;
 21 }a[4003];
 22 int h[1003];
 23 int tot=1;
 24 void con(int x,int y,int v,int c)
 25 {
 26     a[++tot].f=h[x];
 27     h[x]=tot;
 28     a[tot].e=y;
 29     a[tot].v=v;
 30     a[tot].c=c;
 31     a[++tot].f=h[y];
 32     h[y]=tot;
 33     a[tot].e=x;
 34     a[tot].c=-c;
 35     return;
 36 }
 37 struct ahh{
 38     int l,r;
 39 }b[503];
 40 int ls[1003];
 41 int s,t;
 42 queue<int>q;
 43 bool sf[1003];
 44 int dis[1003];
 45 inline bool spfa()
 46 {
 47     memset(sf,0,sizeof(sf));
 48     memset(dis,127,sizeof(dis));
 49     sf[s]=1;dis[s]=0;q.push(s);
 50     while(!q.empty())
 51     {
 52         int x=q.front();q.pop();
 53         for(int i=h[x];i;i=a[i].f)
 54         if(dis[a[i].e]>dis[x]+a[i].c&&a[i].v)
 55         {
 56             dis[a[i].e]=dis[x]+a[i].c;
 57             if(!sf[a[i].e])
 58             {
 59                 sf[a[i].e]=1;
 60                 q.push(a[i].e);
 61             }
 62         }
 63         sf[x]=0;
 64     }
 65     return dis[t]<INF;
 66 }
 67 long long ans=0;
 68 int dfs(int x,int al)
 69 {
 70     sf[x]=1;
 71     if(x==t||!al)return al;
 72     int fl=0;
 73     for(int i=h[x];i;i=a[i].f)
 74     if(dis[a[i].e]==dis[x]+a[i].c&&a[i].v&&!sf[a[i].e])
 75     {
 76         int f=dfs(a[i].e,min(al,a[i].v));
 77         if(f)
 78         {
 79             fl+=f;
 80             al-=f;
 81             ans+=f*a[i].c;
 82             a[i].v-=f;
 83             a[i^1].v+=f;
 84             if(!al)break;
 85         }
 86     }
 87     if(!fl)dis[x]=-INF;
 88     return fl;
 89 }
 90 int main()
 91 {
 92     //freopen("a.in","r",stdin);
 93     int n,k;
 94     scanf("%d%d",&n,&k);
 95     int tol=0;
 96     for(int i=1;i<=n;++i)
 97     {
 98         scanf("%d%d",&b[i].l,&b[i].r);
 99         ls[++tol]=b[i].l;
100         ls[++tol]=b[i].r;
101     }
102     //离散
103     sort(ls+1,ls+tol+1);
104     int len=(unique(ls+1,ls+tol+1)-ls)-1;//用unique去重
105     for(int i=1;i<=n;++i)
106     {
107         int ll=lower_bound(ls+1,ls+len+1,b[i].l)-ls;
108         int rr=lower_bound(ls+1,ls+len+1,b[i].r)-ls;
109         con(ll,rr,1,-(b[i].r-b[i].l));//建边
110     }
111     //
112     s=0,t=len+1;
113     for(int i=1;i<len;++i)
114     con(i,i+1,INF,0);
115     con(s,1,k,0);
116     con(len,t,INF,0);
117     //
118     while(spfa())
119     {
120         sf[t]=1;
121         while(sf[t])
122         {
123             memset(sf,0,sizeof(sf));
124             dfs(s,INF);
125         }
126     }
127     cout<<-ans;//输出再取个负就好了
128     return 0;
129 }

 

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

luogu P3358 最长k可重区间集问题

[luoguP2766] 最长递增子序列问题(最大流)

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

网络流24题22最长k可重线段集问题

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

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