题意
有n个线段((a_i,b_i)),每个线段有一个权值(w_i)。要求选若干个线段,使得数轴上每个点至多被k个线段包含。
建图
可以把权值取负值作为费用求费用流,这题有两种建图方式
-
离散化数据,对每个点i连一条i到i+1的边,流量为k,费用为0。对于所有线段连一条(a_i)到(b_i)的边,流量为1,费用为-(w_i)。那么,对每个点可以选择以这个点为起点的线段或者不选,如果选了就需要花费1个流量,且直到线段终点都只剩下了k-1个流量,所以可以确保每一个点最多被k条线段覆盖。
-
考虑把线段覆盖改为找k个不相交的线段集合。把每个线段拆成两个点,这样就可以对所有不相交的线段进行连边。并且对每个线段的起点终点连边(费用为-w),源点对线段起点连边,线段终点对汇点连边。这样线段集合就表示为了一条增广路。最后在源点或汇点加一个限制(流量为k的边)就可以了。
代码
-
#include<vector> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn=200+5; int a[maxn],b[maxn],ww[maxn]; vector<int>vec; struct Edge{ int v,w,c,next; }edge[maxn*6]; int head[maxn*2],ecnt; void add(int u,int v,int w,int c) { edge[ecnt]=(Edge){v,w,c,head[u]}; head[u]=ecnt++; } const int inf=0x3f3f3f3f; int S,T; int fa[maxn*2],fai[maxn*2]; int dis[maxn*2], vis[maxn*2]; bool spfa() { memset(dis,0x3f,sizeof(dis)); queue<int>q; dis[S]=0; for(q.push(S);!q.empty();q.pop()) { int u=q.front(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!edge[i].w)continue; if(dis[v]>dis[u]+edge[i].c) { dis[v]=dis[u]+edge[i].c; fa[v]=u; fai[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[T]!=inf; } int cost() { int ans=0,flow=inf; for(int u=T;u!=S;u=fa[u]) flow=min(flow,edge[fai[u]].w); for(int u=T;u!=S;u=fa[u]) { edge[fai[u]].w-=flow; edge[fai[u]^1].w+=flow; ans+=flow*edge[fai[u]].c; } return ans; } int main() { int ca; scanf("%d",&ca); while(ca--) { int N,K; vec.clear(); memset(head,-1,sizeof(head)); ecnt=0; scanf("%d%d",&N,&K); for(int i=1;i<=N;i++) { scanf("%d%d%d",&a[i],&b[i],&ww[i]); vec.push_back(a[i]); vec.push_back(b[i]); } sort(vec.begin(),vec.end()); int n=unique(vec.begin(),vec.end())-vec.begin(); vec.resize(n); for(int i=1;i<=N;i++) { a[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin()+1; b[i]=lower_bound(vec.begin(),vec.end(),b[i])-vec.begin()+1; add(a[i],b[i],1,-ww[i]); add(b[i],a[i],0,ww[i]); } for(int i=0;i<=n;i++) { add(i,i+1,K,0); add(i+1,i,0,0); } S=0;T=n+1; int ans=0; while(spfa()) ans+=cost(); printf("%d ",-ans); } return 0; }
-
#include<vector> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn=200+5; int a[maxn],b[maxn],ww[maxn]; struct Edge{ int v,w,c,next; }edge[maxn*maxn*2]; int head[maxn*2],ecnt; void add(int u,int v,int w,int c) { edge[ecnt]=(Edge){v,w,c,head[u]}; head[u]=ecnt++; edge[ecnt]=(Edge){u,0,-c,head[v]}; head[v]=ecnt++; } const int inf=0x3f3f3f3f; int S,T; int fa[maxn*2],fai[maxn*2]; int dis[maxn*2], vis[maxn*2]; bool spfa() { memset(dis,0x3f,sizeof(dis)); queue<int>q; dis[S]=0; for(q.push(S);!q.empty();q.pop()) { int u=q.front(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!edge[i].w)continue; if(dis[v]>dis[u]+edge[i].c) { dis[v]=dis[u]+edge[i].c; fa[v]=u; fai[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[T]!=inf; } int cost() { int ans=0,flow=inf; for(int u=T;u!=S;u=fa[u]) flow=min(flow,edge[fai[u]].w); for(int u=T;u!=S;u=fa[u]) { edge[fai[u]].w-=flow; edge[fai[u]^1].w+=flow; ans+=flow*edge[fai[u]].c; } return ans; } int main() { int ca; scanf("%d",&ca); while(ca--) { int N,K; memset(head,-1,sizeof(head)); ecnt=0; scanf("%d%d",&N,&K); S=0,T=2*N+2; for(int i=1;i<=N;i++) { scanf("%d%d%d",&a[i],&b[i],&ww[i]); add(i*2,i*2+1,1,-ww[i]); //add(i*2,i*2+1,inf,0); add(S+1,i*2,1,0); add(i*2+1,T,1,0); } add(S,S+1,K,0); for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) if(b[i]<=a[j]) add(2*i+1,2*j,inf,0); int ans=0; while(spfa()) ans+=cost(); printf("%d ",-ans); } return 0; }