POJ 3680 Intervals (最小费用最大流+离散化)

来源:互联网 发布:mac地址定位上网位置 编辑:程序博客网 时间:2024/05/21 09:18

Intervals
Time Limit: 5000MS  Memory Limit: 65536K
Total Submissions: 5618  Accepted: 2226

Description

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.

Input

The first line of input is the number of test case.
The first line of each test case contains two integers, N and K (1 ≤ K ≤ N ≤ 200).
The next N line each contain three integers ai, 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

4

3 1
1 2 2
2 3 4
3 4 8

3 1
1 3 2
2 3 4
3 4 8

3 1
1 100000 100000
1 2 3
100 200 300

3 2
1 100000 100000
1 150 301
100 200 300

Sample Output

14
12
100000
100301

 首先需要离散化,去掉重复的点。由于区间最多有N=200个,那么最多有400个点。这里离散化的去重操作直接用STL里的unique,二分查找也偷懒地用了upper_bound...

构图:将每个区间s,e连接容量为1,费用为-v的边。假如离散的点有num个,则对于1~num-1,分别连上i->i+1,流量为K,费用为0。再构造源点,连接1,费用为0,流量为K,用num连接汇点,费用也为0,流量为K。然后跑出来的最小费用流的相反数即是答案。

这样构图的大致原因是:源点与离散化后的点1连了流量为K的边,这就限制了每个区间最多只能取K次了。因为,1除了和它的区间右端点连接以外,还跟2连了一条流量为K,费用为0的边。假如1只在一个区间,且右端点为E(设E>K),那么1的流量除了流向E以外,还有K-1可以流向2。若K=1,显然若1流向了E,则不能再流向2了,只就起到1所在区间只能取一次的目的了。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define SIZE 512#define inf 0x3fffffffusing namespace std;struct node{    int to,val,cost,next;}edge[SIZE*SIZE];int head[SIZE],idx;int dis[SIZE],pre[SIZE],pos[SIZE],que[SIZE*SIZE],fr,len;bool vis[SIZE];int Case,N,K,sc,sk,pt;int st[SIZE],ed[SIZE],v[SIZE];int disc[SIZE],num;void addnode(int from,int to,int val,int cost){    edge[idx].to = to;    edge[idx].val = val;    edge[idx].cost = cost;    edge[idx].next = head[from];    head[from] = idx++;    edge[idx].to = from;    edge[idx].val = 0;    edge[idx].cost = -cost;    edge[idx].next = head[to];    head[to] = idx++;}bool spfa(){    fr = len = 0;    for(int i=0; i<=pt; i++)    {        dis[i] = inf;        pre[i] = pos[i] = -1;        vis[i] = false;    }    dis[sc] = 0;    pre[sc] = sc;    vis[sc] = true;    que[len++] = sc;    while(fr < len)    {        int cur = que[fr++];        vis[cur] = false;        for(int i=head[cur]; i!=-1; i=edge[i].next)        {            int to = edge[i].to;            if(edge[i].val > 0 && dis[to] > dis[cur] + edge[i].cost)            {                dis[to] = dis[cur] + edge[i].cost;                pre[to] = cur;                pos[to] = i;                if(!vis[to])                {                    vis[to] = true;                    que[len++] = to;                }            }        }    }    if(pre[sk] !=-1 && dis[sk] < inf)        return true;    return false;}int CostFlow(){    int flow = 0, cost = 0;    while(spfa())    {        int Min = inf;        for(int i=sk; i!=sc; i=pre[i])            Min = min(Min,edge[pos[i]].val);        flow += Min;        cost += Min*dis[sk];        for(int i=sk; i!=sc; i=pre[i])        {            edge[pos[i]].val -= Min;            edge[pos[i]^1].val += Min;        }    }    return cost;}int main(){    scanf("%d",&Case);    while(Case--)    {        scanf("%d%d",&N,&K);        num = 0;        for(int i=1; i<=N; i++)        {            scanf("%d%d%d",&st[i],&ed[i],&v[i]);            disc[++num] = st[i];            disc[++num] = ed[i];        }        sort(disc+1,disc+1+num);        num = unique(disc+1,disc+1+num)-(disc+1);        idx = 0;        memset(head,-1,sizeof(head));        sc = num+1, sk = num+2, pt = sk+1;        int s,e;        for(int i=1; i<=N; i++)        {            s = upper_bound(disc+1,disc+1+num,st[i])-(disc+1);            e = upper_bound(disc+1,disc+1+num,ed[i])-(disc+1);            addnode(s,e,1,-v[i]);        }        for(int i=1; i<num; i++)            addnode(i,i+1,K,0);        addnode(sc,1,K,0);        addnode(num,sk,K,0);        int ans = CostFlow();        printf("%d\n",-ans);    }    return 0;}


 

 

 

原创粉丝点击