cogs #743


题目链接


最大费用最大流


如何构图?

设源点为 S ,汇点为 T

将所有的端点离散化,

S 点向第一个点连边,每个点向下一个点连边,最后一个点向 T 点连边,流量都为 k ,费用都为 0

对于每条线段,从左端点向右端点连边,流量为 1 <script type="math/tex" id="MathJax-Element-7">1</script>,费用为其长度。

这样就限制了选择的线段数量,同时使得总长度最大。


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <string>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <utility>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
    return;
}
template<class Num>void write(Num x)
{
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    if(!sl) {putchar('0');return;}
    while(sl) putchar(s[--sl]);
}
#define REP(__i,__start,__end) for(int __i = (__start); __i <= (__end); __i++)

const int maxn = 510, node = maxn << 1, edgenum = node << 2, INF = 0x3f3f3f3f;

int n, _k;

struct Edge
{
    int v, cap, cost, next;

    Edge(int v = 0,int cap = 0,int cost = 0,int next = 0):v(v), cap(cap), cost(cost), next(next){}

}edge[edgenum];

#define St first
#define Ed second
std::pair<int, int> seg[maxn];
int bowl[node], bsize;
int head[node], el = 1, S, T, ind;

int dist[node], fr[node], fd[node];

void newedge(int u,int v,int cap,int cost)
{
    edge[++el] = Edge(v, cap, cost, head[u]), head[u] = el;
    edge[++el] = Edge(u, 0, -cost, head[v]), head[v] = el;
}

bool SPFA()
{
    static int line[node];
    static bool hash[node];
    int f = 0, r = 0;

    REP(i, 1, ind) dist[i] = -INF, fr[i] = fd[i] = 0;

    dist[S] = 0, line[r] = S, r = (r + 1)%node;
    hash[S] = true;

    while(f != r)
    {
        int x = line[f], p, calc;
        line[f] = 0, f = (f + 1)%node;
        hash[x] = false;

        for(int i = head[x]; i; i = edge[i].next)
            if(edge[i].cap)
            {
                p = edge[i].v, calc = dist[x] + edge[i].cost;

                if(calc > dist[p])
                {
                    dist[p] = calc, fr[p] = x, fd[p] = i;

                    if(!hash[p])
                    {
                        if(dist[p] <= dist[line[f]])
                            f = (f - 1 + node)%node, line[f] = p;
                        else
                            line[r] = p, r = (r + 1)%node;

                        hash[p] = true;
                    }
                }
            }
    }

    return (dist[T] > -INF);
}

int change(int a,int flow)
{
    if(a != S)
    {
        flow = std::min(flow, edge[fd[a]].cap);
        flow = change(fr[a], flow);

        edge[fd[a]].cap -= flow;
        edge[fd[a]^1].cap += flow;
    }

    return flow;
}

void init()
{
    int u, v;

    read(n), read(_k);

    REP(i, 1, n)
    {
        read(u), read(v);
        seg[i] = std::make_pair(u, v);
    }
}
void prework()
{
    REP(i, 1, n)
    {
        bowl[i<<1] = seg[i].St;
        bowl[(i<<1) - 1] = seg[i].Ed;
    }

    std::sort(bowl + 1, bowl + (n << 1) + 1);
    bsize = std::unique(bowl + 1, bowl + (n << 1) + 1) - (bowl + 1);

    S = bsize + 1, T = bsize + 2, ind = T;

    REP(i, 1, bsize - 1) newedge(i, i + 1, INF, 0);
    newedge(S, 1, _k, 0), newedge(bsize, T, _k, 0);

    REP(i, 1, n)
    {
        int len = seg[i].Ed - seg[i].St;
        seg[i].St = std::lower_bound(bowl + 1, bowl + bsize + 1, seg[i].St) - bowl;
        seg[i].Ed = std::lower_bound(bowl + 1, bowl + bsize + 1, seg[i].Ed) - bowl;
        newedge(seg[i].St, seg[i].Ed, 1, len);
    }

}
int solve()
{
    int maxcost = 0, maxflow = 0;

    while(SPFA())
    {
        maxcost += dist[T];
        maxflow += change(T, INF);
    }

    return maxcost;
}

int main()
{
    freopen("interv.in","r",stdin);
    freopen("interv.out","w",stdout);

    init(), prework(), write(solve());

    fclose(stdin);
    fclose(stdout);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值