网络流/费用流
引用下题解:
lyd:
首先把区间端点离散化,设原来的数值i离散化后的标号是c[i]。这样离散化之后,整个数轴被分成了一段段小区间。
1.建立S和T,从S到离散化后的第一个点连容量K,费用0的边。离散化后的最后一个点到T连容量K、费用0的边。
2.离散化后的相邻点之间(从i到i+1)连容量为K,费用为0的边。
3.输入的区间从离散化后的左端点到右端点连容量1、费用W的边。
感觉好神啊……
其实应该只要把源点到第一个点的流量限制为k应该就可以了……这个构思蛮巧妙的……限制了每个地方最多有k个流出去。
另外,这题是最大费用最大流,所以按上面的建图方式需要改一下预处理和增广的条件,或者就是建图的时候所有的费用取负,再将最后答案取负。
1 Source Code 2 Problem: 3680 User: sdfzyhy 3 Memory: 752K Time: 563MS 4 Language: G++ Result: Accepted 5 6 Source Code 7 8 //BZOJ 3680 9 #include<cmath> 10 #include<vector> 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 #define pb push_back 20 #define CC(a,b) memset(a,b,sizeof(a)) 21 using namespace std; 22 int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();} 25 while(isdigit(ch)) {v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=510,M=100000,INF=~0u>>2; 29 const double eps=1e-8; 30 /*******************template********************/ 31 int n,m,k,ans,a[N],b[N],c[N],w[N]; 32 struct edge{int from,to,v,c;}; 33 struct Net{ 34 edge E[M]; 35 int head[N],next[M],cnt; 36 void ins(int x,int y,int z,int c){ 37 E[++cnt]=(edge){x,y,z,c}; 38 next[cnt]=head[x]; head[x]=cnt; 39 } 40 void add(int x,int y,int z,int c){ 41 ins(x,y,z,c); ins(y,x,0,-c); 42 } 43 int S,T,d[N],Q[M],from[N]; 44 bool inq[N]; 45 bool spfa(){ 46 int l=0,r=-1; 47 F(i,S,T) d[i]=INF; 48 d[S]=0; Q[++r]=S; inq[S]=1; 49 while(l<=r){ 50 int x=Q[l++]; inq[x]=0; 51 for(int i=head[x];i;i=next[i]) 52 if(E[i].v && d[x]+E[i].c<d[E[i].to]){ 53 d[E[i].to]=d[x]+E[i].c; 54 from[E[i].to]=i; 55 if (!inq[E[i].to]){ 56 Q[++r]=E[i].to; 57 inq[E[i].to]=1; 58 } 59 } 60 } 61 return d[T]!=INF; 62 } 63 void mcf(){ 64 int x=INF; 65 for(int i=from[T];i;i=from[E[i].from]) 66 x=min(x,E[i].v); 67 for(int i=from[T];i;i=from[E[i].from]){ 68 E[i].v-=x; 69 E[i^1].v+=x; 70 } 71 ans+=x*d[T]; 72 } 73 void init(){ 74 n=getint(); k=getint(); 75 cnt=1; ans=0; 76 memset(head,0,sizeof head); 77 int x,y; 78 F(i,1,n){ 79 a[i]=c[(i<<1)-1]=getint(); 80 b[i]=c[i<<1]=getint(); 81 w[i]=getint(); 82 } 83 sort(c+1,c+n*2+1); 84 int num=unique(c+1,c+n*2+1)-c-1; 85 S=0; T=num+1; 86 F(i,0,num) add(i,i+1,k,0); 87 F(i,1,n){ 88 a[i]=lower_bound(c+1,c+num+1,a[i])-c; 89 b[i]=lower_bound(c+1,c+num+1,b[i])-c; 90 add(a[i],b[i],1,-w[i]); 91 } 92 while(spfa()) mcf(); 93 printf("%d ",-ans); 94 } 95 }G1; 96 int main(){ 97 #ifndef ONLINE_JUDGE 98 freopen("input.txt","r",stdin); 99 // freopen("output.txt","w",stdout); 100 #endif 101 int T=getint(); 102 while(T--) G1.init(); 103 return 0; 104 }
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 6880 | Accepted: 2859 |
Description
You are given N weighted open intervals. The ith interval covers (ai, bi) and weighs wi. Your task is to pick some of the intervals to maximize the total weights under the limit that no point in the real axis is covered more than k times.
Input
The first line of input is the number of test case.
The first line of each test case contains two integers, N and K (1 ≤ K ≤ N ≤ 200).
The next N line each contain three integers ai, bi, wi(1 ≤ ai < bi ≤ 100,000, 1 ≤ wi ≤ 100,000) describing the intervals.
There is a blank line before each test case.
Output
For each test case output the maximum total weights in a separate line.
Sample Input
4 3 1 1 2 2 2 3 4 3 4 8 3 1 1 3 2 2 3 4 3 4 8 3 1 1 100000 100000 1 2 3 100 200 300 3 2 1 100000 100000 1 150 301 100 200 300
Sample Output
14 12 100000 100301
Source