POJ 3680 Intervals

POJ 3680 Intervals

题目链接

题目大意:给定一些开区间\((a_i,b_i)\),以及区间的价值\(w_i\)。每个点最多被\(k\)个区间覆盖,要求最大化选取的区间的价值和。

非常神奇的费用流。

我们首先将点离散化,假设有\(m\)个点。然后建立超级源\(S\)和超级汇\(T\)

首先连两条边\((S,1,k,0),(m,T,k,0)\),然后相邻两点之间连边\((i,i+1,k,0)\)。然后对于区间\((a,b)\),我们连\((a,b,1,-w)\)。求出最小费用流后取反。

要想搞懂这神奇的建边方式就要先搞懂它是如何满足“每个点最多被\(k\)个区间覆盖”这一限制的。在一个网络中,流入点\(i\)的流量\(flow\)就是\(i\)还可以被覆盖的次数,或者说\(i\)在之前被覆盖了\(k-flow\)次。当我们选择了区间\((a,b)\)后,\((a,b)\)这些节点的剩余流量都减少了,于是我们连\((a,b,1,-w)\),将这部分流量分流出去。

这种带反悔的最优化问题就可以用费用流来高效解决。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

#define ll long long
#define N 405

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

int n,k;
int cas;
struct interval {
	int x,y,w;
}e[N];
int d[N<<1];
struct load {
	int to,next;
	int flow,c;
}s[N<<2];
int h[N],cnt;
int S,T;
void add(int i,int j,int flow,int c) {
	s[++cnt]=(load) {j,h[i],flow,c};h[i]=cnt;
	s[++cnt]=(load) {i,h[j],0,-c};h[j]=cnt;
}
int dis[N];
queue<int>q;
bool in[N];
int fr[N],edge[N];
int ans;
bool spfa() {
	memset(dis,0x3f,sizeof(dis));
	dis[0]=0;
	q.push(0);
	while(!q.empty()) {
		int v=q.front();q.pop();
		in[v]=0;
		for(int i=h[v];i;i=s[i].next) {
			int to=s[i].to;
			if(s[i].flow&&dis[to]>dis[v]+s[i].c) {
				dis[to]=dis[v]+s[i].c;
				fr[to]=v;
				edge[to]=i;
				if(!in[to]) {
					in[to]=1;
					q.push(to);
				}
			}
		}
	}
	if(dis[T]>1e9) return 0;
	int mn=1e9;
	for(int i=T;i;i=fr[i]) mn=min(mn,s[edge[i]].flow);
	for(int i=T;i;i=fr[i]) s[edge[i]].flow-=mn,s[edge[i]^1].flow+=mn;
	ans+=mn*dis[T];
	return 1;
}
int main() {
	cas=Get();
	while(cas--) {
		d[0]=0;
		n=Get(),k=Get();
		for(int i=1;i<=n;i++) {
			int a=Get(),b=Get(),c=Get();
			e[i]=(interval) {a,b,c};
			d[++d[0]]=a;
			d[++d[0]]=b;
		}
		sort(d+1,d+1+d[0]);
		int cc=unique(d+1,d+1+d[0])-d;
		for(int i=1;i<=n;i++) {
			e[i].x=lower_bound(d+1,d+cc,e[i].x)-d;
			e[i].y=lower_bound(d+1,d+cc,e[i].y)-d;
		}
		T=cc;
		memset(h,0,sizeof(h));
		cnt=1;
		add(S,1,k,0),add(T-1,T,k,0);
		for(int i=1;i<T-1;i++) add(i,i+1,k,0);
		for(int i=1;i<=n;i++) {
			add(e[i].x,e[i].y,1,-e[i].w);
		}
		ans=0;
		while(spfa());
		cout<<-ans<<"\n";
	}
	return 0;
}

posted @ 2018-12-05 20:25  hec0411  阅读(160)  评论(0编辑  收藏  举报