POJ 3680 Intervals (费用流经典构图题)

来源:互联网 发布:17年编程语言排行 编辑:程序博客网 时间:2024/05/28 17:05

Description

You are given N weighted open intervals. Theith interval covers (ai,bi) and weighswi. 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.

Input

The first line of input is the number of test case.
The first line of each test case contains two integers,
N andK (1 ≤KN ≤ 200).
The next
N line each contain three integersai,bi,wi(1 ≤ai <bi ≤ 100,000, 1 ≤wi ≤ 100,000) describing the intervals.
There is a blank line before each test case.

Output

For each test case output the maximum total weights in a separate line.

Sample Input

43 11 2 22 3 43 4 83 11 3 22 3 43 4 83 11 100000 1000001 2 3100 200 3003 21 100000 1000001 150 301100 200 300

Sample Output

1412100000100301
题意:给定 N 个带权的开区间,第 i 个区间覆盖(ai, bi),权为 wi。现在要你挑出一些区间使得总权值最大, 并且满足实轴上任意一个点被覆盖不超过 K 次 ,每个区间选一次。注意区间内的点是实数。(1 <= K <= N<= 200, 1 <= ai < bi <= 100,000, 1 <= wi <= 100,000)
建图方法:由于n为200,区间最大100000,所以我们进行离散化,把所有的区间端点离散化到整数1...M,新建源点s=0和汇点t=M+1;对于每个i(0<=i<=M)加边(i,i+1,K,0),这样源点汇点也加进去了。对于每个区间(x,y),离散化后表示为(xx,yy),那么我们加边(xx,yy,1,-wi),因为题目要求最大值,我们将费用变为负数求出最小值,然后再取反就是答案了。此题费用为0已经是最大的费用了...
重点是来简单分析一下为什么这样建图:
丫的,打个换行就不知道怎么描述了!...
首先,如果你要限制一个区间(x,y)内的点最多被覆盖K次,我们可以在端点x前面和端点y后面加一条辅助边(暂且说成辅助边吧),容量为K,使之成为这样:
i---x-...-y---j,此时限制i---x为辅助边,容量为K,y---j为辅助边,容量为K,如果已知有一段可选择区间为(x,y,1,-wi),此时流量只会从(x,y,1,-wi)流过去,因为费用小。那么i---x的容量-1,y---j的容量也-1,假使题目中有K个这样的区间,跑完以后i到j就流不通了,说明区间(x,y)内的所有数都被覆盖了K次了。这样便可以慢慢试着推广到此题了,所有的边(i,i+1,K,0),i到i+1充当着区间和辅助边的作用,如果选用边(a,b,1,-wi),那么(a-1,a,K,0)和(b,b+1,K,0)这两条边就充当了辅助边的效果,保护着(a,b)区间内的数被覆盖不超过K次。
虽然说得自己都乱了,但是第一次做这种题,有必要记录一下此时的想法。
#include<cstdio>#include<string.h>#include<queue>#include<algorithm>#define maxn 510#define inf 0x3f3f3fusing namespace std;struct node{    int st;    int en;    int flow,cost;    int next;}E[maxn*maxn];int num;int p[maxn];void init(){    memset(p,-1,sizeof p);    num=0;}void add(int st,int en,int flow,int cost){    E[num].st=st;    E[num].en=en;    E[num].flow=flow;    E[num].cost=cost;    E[num].next=p[st];    p[st]=num++;    E[num].st=en;    E[num].en=st;    E[num].flow=0;    E[num].cost=-cost;    E[num].next=p[en];    p[en]=num++;}int pre[maxn];int dis[maxn];bool fg[maxn];bool spfa(int st,int en){    for(int i=0;i<=en;i++)        fg[i]=0,dis[i]=inf,pre[i]=-1;    queue<int>q;    q.push(st);    fg[st]=1;    dis[st]=0;    while(!q.empty())    {        int u=q.front();        q.pop();        fg[u]=0;        for(int i=p[u];i+1;i=E[i].next)        {            int v=E[i].en;            if(E[i].flow&&dis[v]>dis[u]+E[i].cost)            {                dis[v]=dis[u]+E[i].cost;                pre[v]=i;                if(!fg[v])                {                    fg[v]=1;                    q.push(v);                }            }        }    }    if(dis[en]<inf)        return 1;    return 0;}int solve(int st,int en){    int ans=0;    while(spfa(st,en))    {        int d=inf;        for(int i=pre[en];i+1;i=pre[E[i].st])            d=min(d,E[i].flow);        for(int i=pre[en];i+1;i=pre[E[i].st])        {            E[i].flow-=d;            E[i^1].flow+=d;            ans+=d*E[i].cost;        }    }    return ans;}int a[500];int l[300],r[300],c[300];int b[100010];int main(){    int T;    scanf("%d",&T);    while(T--)    {        init();        int n,k;        scanf("%d%d",&n,&k);        int num=0;        for(int i=1;i<=n;i++)        {            scanf("%d%d%d",&l[i],&r[i],&c[i]);            a[++num]=l[i];            a[++num]=r[i];        }        sort(a+1,a+num+1);        num=unique(a+1,a+num+1)-a-1;///去重        for(int i=1;i<=num;i++)            b[a[i]]=i;        int s=0,t=num+1;        for(int i=0;i<=num;i++)            add(i,i+1,k,0);        for(int i=1;i<=n;i++)        {            add(b[l[i]],b[r[i]],1,-c[i]);        }        printf("%d\n",-solve(s,t));    }    return 0;}

0 0
原创粉丝点击