1. 程式人生 > >「網絡流24題」「LuoguP3358」 最長k可重區間集問題

「網絡流24題」「LuoguP3358」 最長k可重區間集問題

取反 spa 區間 out freopen clu 內存 ted sizeof

題目描述

技術分享圖片

對於給定的開區間集合 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可重區間集問題