1. 程式人生 > >最長k可重區間集問題

最長k可重區間集問題

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可重區間集問題