最長k可重區間集問題
阿新 • • 發佈:2018-01-04
ace blog register 一個 inf for wap ans string
最長k可重區間集問題
題目鏈接 https://www.luogu.org/problemnew/show/3358
做法
所有點向下一個點連容量為k費用為0的邊
l和r連容量為1費用為區間長度的邊
然後跑最大流最大費用流
(最大費用就是把邊權取相反數跑最小費用
最後再輸出最終費用的相反數)
思考
在整張圖中,只有l - >r的邊有費用
而且費用為區間長度
(i->i+1費用為0)
所以跑最大費用也就是求最長區間
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define ul unsigned long long
#define rg register int
#define ll long long
#define il inline
#define INF 2147483647
#define SZ 10000000
using namespace std;
int n,N,k,s,t,a[SZ],l[SZ],r[SZ];
/* N : 原數組大小
n : 離散化之後的數組大小
a[] : 離散數組
k : 可重叠數
l , r 所給區間左端點和右端點
*/
struct Edge{int to,nxt,w,c;}e[SZ];
int Ehead[SZ],pv[SZ],pe[SZ],Ecnt=2;
il void Eadd(int u,int v,int w,int cost)
{
e[Ecnt]=(Edge){v,Ehead[u],w,cost};
Ehead[u]=Ecnt++;
e[Ecnt]=(Edge){u,Ehead[v],0,-cost};
Ehead[v]=Ecnt++;
}
/* 加邊函數
pv[i] : spfa時使得i點dis值松弛的節點
(最短路的上一節點)
pe[i] : i與pv[i]連接的邊
e[i].w : 流量
e[i].c : 費用
*/
// 費用流板子 ‘_‘↓↓↓
ll dis[SZ];
int vis[SZ];
queue <int> Q;
bool spfa()
{
memset(dis,63,sizeof(dis));
dis[s]=0; Q.push(s);
while(!Q.empty())
{
rg u=Q.front();
Q.pop();
for(rg i=Ehead[u];i;i=e[i].nxt)
{
rg v=e[i].to;
if((e[i].w)&&(dis[v]>dis[u]+e[i].c))
{
dis[v]=dis[u]+e[i].c;
pe[v]=i;
pv[v]=u;
if(!vis[v])
{
vis[v]=1;
Q.push(v);
}
}
}
vis[u]=0;
}
return dis[t]<dis[0];
}
il void costflow()
{
ll Ans=0;
while(spfa())
{
rg di=INF;
for(rg i=t;i!=s;i=pv[i])
di=min(di,e[pe[i]].w);
for(rg i=t;i!=s;i=pv[i])
{
e[pe[i]].w-=di;
e[pe[i]^1].w+=di;
Ans+=1ll*di*e[pe[i]].c;
}
}
printf("%lld",-Ans);
}
// 費用流板子 ‘_‘↑↑↑
int main()
{
scanf("%d%d",&N,&k);
for(rg i=1;i<=N;++i)
{
scanf("%d%d",&l[i],&r[i]);
if(l[i]>r[i]) swap(l[i],r[i]);
a[i]=l[i];a[i+N]=r[i];
}
sort(a+1,a+N+N+1);
n=unique(a+1,a+N+N+1)-a-1;
for(rg i=1;i<=N;++i)
{
rg L=lower_bound(a+1,a+n+1,l[i])-a;
rg R=lower_bound(a+1,a+n+1,r[i])-a;
Eadd(L,R,1,l[i]-r[i]);
}
/* 利用unique和lower_bound離散化
原理是把輸入到l[i]與r[i]出現的所有數字
排完序後利用unique去重
註意那些+1-1什麽的
*/
for(rg i=1;i<n;++i)
Eadd(i,i+1,INF,0);
s=n+1;t=n+2;
Eadd(s,1,k,0);
Eadd(n,t,k,0);
costflow();
while(1);
return 0;
}
最長k可重區間集問題