[网络流24题(3/24)] 最长k可重区间集问题(洛谷P3358)
分析:
这是一个非常经典的费用流的模型。
首先因为题目中限制我们每个点最多只能选取\(k\)次,因此,因为会有\(k\)次的限制,因此我们不妨用最大流进行限流,即我们将源点拆成两个点\(S_0\)以及\(S_1\),从\(S_0\)点向\(S_1\)点连一条流量为k,费用为\(0\)的边。代表最多有大小为\(k\)的流经过所有的边。这样我们就能够保证,最终通过终点的流量被限死在k,而又因为要求的是最大价值,因此我们需要求的是最大费用最大流,这个我们只需要将价值变成负数。
因为最多会有\(n\)对区间,\(2n\)个点,因此我们考虑将着\(2n\)个点离散化。离散化后,我们将这离散化后的\(2n\)个点中离散化后相邻的点都连一条流量为\(inf\),费用为\(0\)的边,代表相邻的点都可以互相到达。之后我们再将之前的\(n\)对区间的每一个区间\([l,r]\),将点\(l\)和点\(r\)之间连一条费用为\(-len_{lr}\),流量为\(1\)的边,代表如果要选取当前区间,则将会花费\(-len{lr}\)的费用以及区间中的所有点都将占用\(1\)点流量。建立好图之后,我们跑一边最小费用最大流之后取最小费用的相反数即可。
代码:
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define maxn 1006
#define maxm 10005
using namespace std;
int head[maxn],cnt=0;
int dis[maxn],vis[maxn],sp,ep,maxflow,cost;
int n,k;
const int INF=0x3f3f3f3f;
struct Node{
int to,next,val,cost;
}q[maxm<<1];
int L[maxn],R[maxn];
vector<int>vec;
void init(){
memset(head,-1, sizeof(head));
cnt=2;
maxflow=cost=0;
}
void addedge(int from,int to,int val,int cost){
q[cnt].to=to;
q[cnt].next=head[from];
q[cnt].val=val;
q[cnt].cost=cost;
head[from]=cnt++;
}
void add_edge(int from,int to,int val,int cost){
addedge(from,to,val,cost);
addedge(to,from,0,-cost);
}
bool spfa(){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[sp]=0;
vis[sp]=1;
queue<int>que;
que.push(sp);
while(!que.empty()){
int x=que.front();
que.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if(dis[to]>dis[x]+q[i].cost&&q[i].val){
dis[to]=dis[x]+q[i].cost;
if(!vis[to]){
que.push(to);
vis[to]=1;
}
}
}
}
return dis[ep]!=0x3f3f3f3f;
}
int dfs(int x,int flow){
if(x==ep){
vis[ep]=1;
maxflow+=flow;
return flow;
}//可以到达t,加流
int used=0;//该条路径可用流量
vis[x]=1;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if((vis[to]==0||to==ep)&&q[i].val!=0&&dis[to]==dis[x]+q[i].cost){
int minflow=dfs(to,min(flow-used,q[i].val));
if(minflow!=0){
cost+=q[i].cost*minflow;
q[i].val-=minflow;
q[i^1].val+=minflow;
used+=minflow;
}
//可以到达t,加费用,扣流量
if(used==flow)break;
}
}
return used;
}
int mincostmaxflow(){
while(spfa()){
vis[ep]=1;
while(vis[ep]){
memset(vis,0,sizeof(vis));
dfs(sp,INF);
}
}
return maxflow;
}
int main()
{
scanf("%d%d",&n,&k);
init();
for(int i=1;i<=n;i++){
scanf("%d%d",&L[i],&R[i]);
if(L[i]>R[i]) swap(L[i],R[i]);
vec.push_back(L[i]);
vec.push_back(R[i]);
}
sort(vec.begin(),vec.end());
int sz=vec.size();
sp=sz+1,ep=sz+2;
add_edge(sp,1,k,0);
add_edge(sz,ep,k,0);
for(int i=1;i<sz;i++) add_edge(i,i+1,k,0);
for(int i=1;i<=n;i++){
int l=lower_bound(vec.begin(),vec.end(),L[i])-vec.begin();
int r=lower_bound(vec.begin(),vec.end(),R[i])-vec.begin();
add_edge(l+1,r+1,1,vec[l]-vec[r]);
}
mincostmaxflow();
printf("%d\n",-cost);
return 0;
}