POJ 3680 Intervals 神奇的构图

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.

题意:

给出n个区间及其权值,从中选出一些区间使它们的权值合最大,给出一个k告诉你任意一个点最多可以被覆盖k次。

解题思路:

区间范围有点大,但是n不大,离散化一下,排个序,去个重,把区间端点从小到大编号构图:

1.连接第i和i+1个端点,容量设置为k,权值为0

2.连接第一个端点和源点,连接最后的端点和汇点,容量为k,权值为0(这样可以保护每个区间不被超过k次使用)

3.连接所有区间端点(左边的连向右边的),容量为1,权值为该区间的权值*(-1),(用这个跑最小费用流可以得出最大费用的相反数)(一个区间只能使用一次)

画个图大概就能理解为什么要这样连接了。

跑一遍最小费用流得出答案。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<list>
#include<cmath>
#include<string>
#include<iomanip>
using namespace std;
const int MAXN = 205*2;
const int MAXM = 2*(205*2+205);
const int INF = 0x3f3f3f3f;
int n,k,num;
int l[205],r[205],c[205];
int a[205*2],b[100010];   //a用来存节点,b用来存编号
struct Edge
{
    int u,v,cap,cost,nex;
}edge[MAXM];
int sumFlow;

int e_max;
int fir[MAXN], dist[MAXN], pre[MAXN];
bool vis[MAXN];
int q[9999999];
void init()
{
    e_max=0;
    memset(fir,-1,sizeof(fir));
}
void add_edge(int u,int v,int cap,int cost)
{
    edge[e_max].u=u;edge[e_max].v=v;edge[e_max].cap=cap;edge[e_max].cost=cost;
    edge[e_max].nex=fir[u];fir[u]=e_max++;
    edge[e_max].u=v;edge[e_max].v=u;edge[e_max].cap=0;edge[e_max].cost=-cost;
    edge[e_max].nex=fir[v];fir[v]=e_max++;
}
bool SPFA(int s,int t)
{
    int i,u,v;
    memset(vis,false,sizeof vis );
    memset(pre,-1,sizeof pre );
    memset(dist,INF,sizeof dist);
    vis[s]=true;
    dist[s]=0;
    q[0]=s;
    int f=0,r=1;
    while(f<r)
    {
        u=q[f++];
        vis[u]=false;
        for(i=fir[u];i!=-1;i=edge[i].nex)
        {
            v=edge[i].v;
            if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost)
            {
                dist[v]=dist[u]+edge[i].cost;
                pre[v]=i;
                if(!vis[v])
                {
                        q[r++]=v;
                        vis[v]=true;
                }
            }
        }
    }
    if(dist[t]==INF)
        return false;
    return true;
}
int ford_fulkerson(int s,int t)
{
    int flow=0; 
    int i,minflow,mincost;
    mincost=0;
    while(SPFA(s,t))
    {
        minflow=INF+1;
        for(i=pre[t];i!=-1;i=pre[edge[i].u])
            if(edge[i].cap<minflow)
                minflow=edge[i].cap;
        flow+=minflow;
        for(i=pre[t];i!=-1;i=pre[edge[i].u])
        {
            edge[i].cap-=minflow;
            edge[i^1].cap+=minflow;
        }
        mincost+=dist[t]*minflow;
    }
    sumFlow=flow; 
    return mincost;
}

void read()
{
        num=0;
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
                cin>>l[i]>>r[i]>>c[i];
                a[++num]=l[i];
                a[++num]=r[i];
        }

}
int solve()
{
        init();
        sort(a+1,a+1+num);
        num=unique(a+1,a+num+1)-a-1;   //去重
        for(int i=1;i<=num;i++)
                b[a[i]]=i;
        for(int i=0;i<=num;i++)
                add_edge(i,i+1,k,0);
        for(int i=1;i<=n;i++)
                add_edge(b[l[i]],b[r[i]],1,-c[i]);
        return (-1)*ford_fulkerson(0,num+1);
}
int main()
{
        int T;
        cin>>T;
        while(T--)
        {
               read();
               cout<<solve()<<endl;
        }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值