区间K覆盖(费用流)

原题: http://poj.org/problem?id=3680

题意:

你想要选择一些区间并得到这些区间的cost,但是要求任意一个点都最多被K个区间覆盖,问最大cost

解析:

因为端点被覆盖的次数一定大于中间点,所以只需要考虑中间点即可。(离散化)

首先连上sp-1-2-…-n-ep的边,容量为K,花费为0。那么之后怎么跑每个点都只会被经过K次。对于区间[L,R],连一条L到R的边,容量为1,花费为-cost(因为要花费最大,而用得是最小花费板子,所以取反)。

这样到没有到达流量上限时,会优先跑-cost这条边,也就得到了在流量小于K前提下的最大花费。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long
#define debug(i) printf("%d\n",i)
const int maxn=2009;
const int inf=0x3f3f3f3f;
int head[maxn],nex[maxn],to[maxn],now;
int val[maxn],cost[maxn];
void add(int a,int b,int v,int c){// 反边流量0,花费-c
    to[now]=b;val[now]=v;cost[now]=c;
    nex[now]=head[a];head[a]=now++;
    to[now]=a;val[now]=0;cost[now]=-c;
    nex[now]=head[b];head[b]=now++;
}

int sp,ep;
int dis[maxn];
bool vis[maxn];
int pre[maxn];

bool SPFA(int &flow,int &cos){
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    memset(dis,0x3f,sizeof(dis));
    queue<int>Q;
    dis[sp]=0;vis[sp]=1;Q.push(sp);
    int d=inf;
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        vis[p]=0;
        for(int i=head[p];~i;i=nex[i]){
            int u=to[i];
            if(val[i]>0&&dis[u]-cost[i]>dis[p]){
                dis[u]=dis[p]+cost[i];
                pre[u]=i;
                if(!vis[u]){
                    vis[u]=1;
                    Q.push(u);
                }
            }
        }
    }
    if(dis[ep]==inf)return 0;
    for(int i=pre[ep];~i;i=pre[to[i^1]]){
        d=min(d,val[i]);
    }
    for(int i=pre[ep];~i;i=pre[to[i^1]]){
        val[i]-=d;
        val[i^1]+=d;
        cos+=cost[i]*d;
    }
    flow+=d;
    return 1;
}
int MinCost(){
    int flow=0,cost=0;
    while(SPFA(flow,cost));
    return cost;
}
void init(){
    now=0;
    memset(head,-1,sizeof(head));
}
int a[maxn],b[maxn],tmp[maxn];
int c[maxn];
int main(){
    int t;scanf("%d",&t);
    while(t--){
        init();
        int n;int k;scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&a[i],&b[i],c+i);
            tmp[i*2-1]=a[i];
            tmp[i*2]=b[i];
        }
        sort(tmp+1,tmp+1+2*n);
        int num=unique(tmp+1,tmp+1+2*n)-tmp-1;
        for(int i=1;i<=n;i++){
            a[i]=lower_bound(tmp+1,tmp+1+num,a[i])-tmp;
            b[i]=lower_bound(tmp+1,tmp+1+num,b[i])-tmp;
        }
        sp=0,ep=num+1;
        add(sp,1,k,0);
        add(num,ep,k,0);
        for(int i=1;i<num;i++){
            add(i,i+1,k,0);
        }
        for(int i=1;i<=n;i++){
            add(a[i],b[i],1,-c[i]);
        }
        int ans=-MinCost();
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/89669696