POJ 3680 区间k覆盖

Intervals

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.

题意:给你n个开区间 ( a i , b i ) (a_i,b_i) ,每个区间有一个权值 w i w_i ,现让你选出权值之和尽量大的一些区间,使得任意一个数最多被k个区间覆盖

建图技巧:首先对区间的左右端点离散化,假设离散化后有cnt个不同点,标号为1 ~ cnt,设一个源点0,汇点cnt+1,在任意相邻的两个点(i,i+1)之间建一条边,容量为k(除了源点和1号节点之间必须为k,其他可为无穷大),权值为0,对于每个区间 ( a i , b i ) (a_i,b_i) ,在 ( a i , b i ) (a_i,b_i) 之间连一条容量为1,权值为- w i w_i 的边,跑最小费用流即可

理解:首先 ( a i , b i ) (a_i,b_i) 之间的边容量为1可以保证这个区间只会被取1次,取之后权值就会被加上去,然后由于源点0号节点和1号节点之间有一条容量为k的边,即可保证每个左端点的流量最多为k(实数域上在区间内的点和左端点同,当一个点被覆盖时,必然在它的左侧某处被分流,这个点能够有的最大流量会减去它已经被覆盖的次数,而到了一个区间的右端点这个流量会加回来),即被覆盖次数不会超过k次

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAXN 410
#define MAXM 610
using namespace std;
const int INF = 0x3f3f3f3f;
int tot,head[MAXN],cnt;
struct edge
{
    int u,v,c,w,nxt;
}edg[MAXM<<1];
inline void addedg(int u,int v,int c,int w)
{
    edg[tot].u = u;
    edg[tot].v = v;
    edg[tot].c = c;
    edg[tot].w = w;
    edg[tot].nxt = head[u];
    head[u] = tot++;
}
inline void add(int u,int v,int c,int w)
{
    addedg(u,v,c,w);
    addedg(v,u,0,-w);
}
int n,m,vis[MAXN],d[MAXN],pre[MAXN],path[MAXN],cost,k;
//d用来存最短路,pre用来存路径,path用来存用了哪条边,cost用来保存最小费用
inline bool SPFA(int st,int ed)
{
    memset(d,0x3f,sizeof(int)*(cnt+3));
    memset(pre,-1,sizeof(int)*(cnt+3));
    memset(path,-1,sizeof(int)*(cnt+3));
    memset(vis,0,sizeof(int)*(cnt+3));
    queue<int> qu;
    d[st] = 0;
    vis[st] = 1;
    qu.push(st);
    while(!qu.empty())
    {
        int u = qu.front();
        qu.pop();
        vis[u] = 0;
        for(int i = head[u];i != -1;i = edg[i].nxt)
        {
            int v = edg[i].v;
            if(d[u] + edg[i].w < d[v] && edg[i].c > 0)
            {
                d[v] = d[u] + edg[i].w;
                pre[v] = u;
                path[v] = i;
                if(!vis[v])
                {
                    vis[v] = 1;
                    qu.push(v);
                }
            }
        }
    }
    return pre[ed] != -1;
}
inline int minCostMaxFlow(int st,int ed)
{
    int flow = 0;
    while(SPFA(st,ed))
    {
        int minn = INF;
        for(int i = ed;i != st;i = pre[i])
            minn = min(minn,edg[path[i]].c);//求出新增加的流量
        for(int i = ed;i != st;i = pre[i])
        {
            edg[path[i]].c -= minn;
            edg[path[i]^1].c += minn;
        }
        if(d[ed] >= 0) //保证费用最小,去掉后保证流量最大
            break;
        flow += minn;
        cost += minn * d[ed];
    }
    return flow;
}
inline void init()
{
    tot = cost = 0;
    memset(head,-1,sizeof(int)*(cnt+3));
}
struct node
{
    int l,r,w;
}nod[MAXN];
int a[MAXN];
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d",&n,&k);
        cnt = 0;
        for(int i = 1;i <= n;++i)
        {
            scanf("%d%d%d",&nod[i].l,&nod[i].r,&nod[i].w);
            a[++cnt] = nod[i].l;
            a[++cnt] = nod[i].r;
        }
        sort(a+1,a+cnt+1);
        cnt = unique(a+1,a+cnt+1) - a-1;
        init();
        int s = 0,t = cnt+1;
        for(int i = 0;i < t;++i)
            add(i,i+1,k,0);
        for(int i = 1;i <= n;++i)
        {
            nod[i].l = lower_bound(a+1,a+cnt+1,nod[i].l)-a;
            nod[i].r = lower_bound(a+1,a+cnt+1,nod[i].r)-a;
            add(nod[i].l,nod[i].r,1,-nod[i].w);
        }
        minCostMaxFlow(s,t);
        printf("%d\n",-cost);
    }
    return 0;
}
发布了50 篇原创文章 · 获赞 3 · 访问量 3116

猜你喜欢

转载自blog.csdn.net/xing_mo/article/details/103979565