版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/82744109
题目链接:http://poj.org/problem?id=3762
题意:
给你n个区间,每个区间都有一个自带的权值,你要从里面选取若干个区间,注意每个区间只可以被选择一次,使得每个数轴上没有点可以被使用超过K次并且使得到的权值最大。
做法:
第一次学区间K覆盖,学到了这个神奇的K覆盖。让我用一个丑丑的图来解释一下网上那些题解里面讲的。
这道题网上是这么解释的,咳咳最小费用最大流,先讲点进行离散化,在将对应区间的点之间连边,边的容量为1权值取负(挺好理解的因为要最大费用但板子是最小费用所以取反就好),这样保证了每个区间都只会被取到一次(下图标红的序号2),同时,像下图中1连向5的边一下,如果流量从这里通过,那么就会直接略过2,3,4这三个点的影响,从5开始还能继续流,而从点i还要连向i+1,容量为k,费用为0,其实这里的容量可以大于等于k,因为在超级源点和点1之间我们就已经连了k,最后一个点和汇点也要连k,所以已经保证好了,不过网上都是这么说的那我也就这样画了。这样保证如果这个点为起始点不能取到最优那么可以从它包括了的更优的区间里面找更优的起始点,如下图。
感觉画了图好理解的多了。
#include <map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=600;
const int maxm=2000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt;
int n,m,sp,tp,k;
struct node{
int to,cap,next;
int cost;
}e[maxm];
map<int,int> mp;
void add(int from,int to,int cap,int cost){
e[cnt].to=to; e[cnt].cap=cap;
e[cnt].cost=cost; e[cnt].next=head[from];
head[from]=cnt++;
e[cnt].to=from; e[cnt].cap=0;
e[cnt].cost=-cost; e[cnt].next=head[to];
head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
queue<int> q;
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
dis[s]=0; q.push(s);
vis[s]=1;
int d=inf;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[t]==inf){
return false;
}
for(int i=pre[t];~i;i=pre[e[i^1].to]){
d=min(d,e[i].cap);
}
for(int i=pre[t];~i;i=pre[e[i^1].to]){
e[i].cap-=d;
e[i^1].cap+=d;
cost+=e[i].cost*d;
}
flow+=d;
return true;
}
int mcmf(int s,int t){
int flow=0;
int cost=0;
while(spfa(s,t,flow,cost)){
//cout<<flow<<" "<<cost<<endl;
}
return cost;
}
struct nodes{
int u,v;
ll c;
}ee[2500];
int main(){
int t;
cin>>t;
while(t--){
int tmp[1005],numtmp=0; mp.clear();
scanf("%d%d",&n,&k);
cnt=0;
memset(head,-1,sizeof(head));
sp=0;
for(int i=0;i<n;i++){
scanf("%d%d%lld",&ee[i].u,&ee[i].v,&ee[i].c);
tmp[numtmp++]=ee[i].u,tmp[numtmp++]=ee[i].v;
}
sort(tmp,tmp+numtmp);
int cc=unique(tmp,tmp+numtmp)-tmp;
numtmp=0;
for(int i=0;i<cc;i++){
mp[tmp[i]]=++numtmp;
}
for(int i=0;i<n;i++){
int u=mp[ee[i].u],v=mp[ee[i].v];
add(u,v,1,-ee[i].c);
}
for(int i=1;i<numtmp;i++)
add(i,i+1,k,0);
tp=numtmp+1;
add(sp,1,k,0); add(numtmp,tp,k,0);
printf("%d\n",-mcmf(sp,tp));
}
return 0;
}