POJ3680 Intervals 离散化+费用流

有多个区间,每个区间都是开区间,每一个区间都有一个权值,现在要保证每一个点不被覆盖k次以上,并且要是所有区间权值和最大

将端点离散化

添加源汇

汇点与数轴上最后一个点连 容量为k,费用0

源点与数轴上第一个点连,容量为k,费用为0

这两条弧用来保证一个点不被重复覆盖k次  ( 其实我们每一次增广网络的时候相当于从起点到终点画一条线,每次选中尽量多的不重叠的区间,这样最多重复画k次那么就一定不会有点被覆盖k次以上)


然后相邻的点 i 和 i+1 连一条边 容量 INF , 费用0

然后区间(a,b)

相应点连边,容量为 1 费用为 -w

最后跑一边最小费用即可

答案取反。


此题建图很经典


Intervals
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 6241 Accepted: 2537

Description

You are given N weighted open intervals. The ith interval covers (aibi) 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 aibiwi(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

Source



#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>

using namespace std;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;

#define MAXN 1000
#define MAXM 100000
#define INF 0xFFFFFF

struct edge
{
	int to,c,w,next;
};

edge e[MAXM];
bool in[MAXN];
int head[MAXN],dis[MAXN],pre[MAXN],en,maxflow,mincost;
int vn,st,ed;
int n,k;

void add(int a,int b,int c,int d)
{
	e[en].to=b;
	e[en].c=c;
	e[en].w=d;
	e[en].next=head[a];
	head[a]=en++;
	e[en].to=a;
	e[en].c=0;
	e[en].w=-d;
	e[en].next=head[b];
	head[b]=en++;
}

bool spfa(int s)
{
	queue<int> q;
	for(int i=0;i<=vn;i++)
	{
		dis[i]=INF;
		in[i]=false;
		pre[i]=-1;
	}
	dis[s]=0;
	in[s]=true;
	q.push(s);
	while(!q.empty())
	{
		int tag=q.front();
		in[tag]=false;
		q.pop();
		for(int i=head[tag];i!=-1;i=e[i].next)
		{
			int j=e[i].to;
			if(e[i].w+dis[tag]<dis[j] && e[i].c)
			{
				dis[j]=e[i].w+dis[tag];
				pre[j]=i;
				if(!in[j])
				{
					q.push(j);
					in[j]=true;
				}
			}
		}
	}
	if(dis[ed]==INF)
		return false;
	return true;
}

void update()
{
	int flow=INF;
    for (int i=pre[ed];i!=-1;i=pre[e[i^1].to])
		if(e[i].c<flow) flow=e[i].c;
    for (int i=pre[ed];i!=-1;i=pre[e[i^1].to])
    {
		e[i].c-=flow,e[i^1].c+=flow;
	}
    maxflow+=flow;
    mincost+=flow*dis[ed];
}

void mincostmaxflow()
{
	maxflow=0,mincost=0;
	while(spfa(st)){
		update();

	}
}

int hash[600];
int p;
int l[600],r[600],w[600];

int getHash(int x){
    int l=0,r=p;
    while(l<=r){
        int m=(l+r)/2;
        if(hash[m]==x)
            return m;
        else if(hash[m]>x)
            r=m-1;
        else if(hash[m]<x)
            l=m+1;
    }
    return -1;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        p=0;
        //离散化
        for(int i=0;i<n;i++){
            scanf("%d%d%d",&l[i],&r[i],&w[i]);
            hash[p++]=l[i];
            hash[p++]=r[i];
        }
        sort(hash,hash+p);
        p=unique(hash,hash+p)-hash;
        //建图
        memset(head,-1,sizeof(head));en=0;
        st=0,ed=p+1,vn=ed+1;
        add(st,1,k,0);
        add(p,ed,k,0);
        for(int i=1;i<p;i++)
            add(i,i+1,INF,0);
        for(int i=0;i<n;i++)
        {
            int ll=getHash(l[i]);
            int rr=getHash(r[i]);
            add(ll+1,rr+1,1,-w[i]);
        }
        mincostmaxflow();
        printf("%d\n",-mincost);

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值