zoukankan      html  css  js  c++  java
  • POJ 3680 Intervals

    POJ_3680

        一开始想的是将区间放到一边,然后点放到另一边,区间和覆盖的点连边做费用流,但这样很明显是错误的,因为在最大流时源点流入区间的边不一定是满流的,也就是说线段选择性地覆盖了若干个点,这显然是不科学的。

        在参考了别人的思路之后,发现保证每个点被覆盖K次,不仅可以每个点都连一条容量为K边到汇点,还可以每个点只连一条容量为K的边到后一个点,相当于把这些点串联起来,这样也可以保证每个点至多被覆盖K次。至于如何描述选择了一个区间(a,b),可以连一条a到b的容量为1费用为w的边,这样只要再额外限定从源点出发的或者是流到汇点的容量为K,那么对于任何一个小区间就最多只会有K条流流过,这样就保证了每个点至多被覆盖K次。最后做最大费用最大流即可,因为原图没有环,所以可以不必考虑有正圈的情况。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXD 410
    #define MAXM 1210
    #define INF 0x3f3f3f3f
    #define NINF 0xc3c3c3c3
    const int Q = 405;
    int N, M, K, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM], cost[MAXM];
    int S, T, tx[MAXD], q[MAXD], inq[MAXD], dis[MAXD], pre[MAXD];
    struct Seg
    {
        int x, y, w;
    }seg[MAXD];
    void init()
    {
        int i;
        scanf("%d%d", &N, &K);
        for(i = 0; i < N; i ++)
        {
            scanf("%d%d%d", &seg[i].x, &seg[i].y, &seg[i].w);
            tx[i << 1] = seg[i].x, tx[i << 1 | 1] = seg[i].y;
        }
        std::sort(tx, tx + N * 2);
        for(i = M = 1; i < N * 2; i ++) if(tx[i] != tx[i - 1]) tx[M ++] = tx[i];
        tx[M] = INF;
    }
    int BS(int x)
    {
        int mid, min = 0, max = M;
        for(;;)
        {
            mid = min + max >> 1;
            if(mid == min) break;
            if(tx[mid] <= x) min = mid;
            else max = mid;
        }
        return mid;
    }
    void add(int x, int y, int f, int c)
    {
        v[e] = y, flow[e] = f, cost[e] = c;
        next[e] = first[x], first[x] = e ++;
    }
    void build()
    {
        int i, x, y;
        S = 0, T = M;
        memset(first, -1, sizeof(first[0]) * (T + 1)), e = 0;
        for(i = 0; i < M; i ++)
            add(i, i + 1, K, 0), add(i + 1, i, 0, 0);
        for(i = 0; i < N; i ++)
        {
            x = BS(seg[i].x), y = BS(seg[i].y);
            add(x, y, 1, seg[i].w), add(y, x, 0, -seg[i].w);
        }
    }
    int bfs()
    {
        int i, x, front = 0, rear = 0;
        memset(dis, 0xc3, sizeof(dis[0]) * (T + 1));
        dis[S] = 0, pre[S] = -1, q[rear ++] = S;
        memset(inq, 0, sizeof(inq[0]) * (T + 1));
        while(front != rear)
        {
            x = q[front ++], inq[x] = 0;
            front > Q ? front = 0 : 0;
            for(i = first[x]; i != -1; i = next[i])
                if(flow[i] && dis[v[i]] < dis[x] + cost[i])
                {
                    dis[v[i]] = dis[x] + cost[i], pre[v[i]] = i;
                    if(!inq[v[i]])
                    {
                        q[rear ++] = v[i], inq[v[i]] = 1;
                        rear > Q ? rear = 0 : 0;
                    }
                }
        }
        return dis[T] != NINF;
    }
    void solve()
    {
        int i, c = 0, a;
        build();
        while(bfs())
        {
            for(i = pre[T], a = INF; i != -1; i = pre[v[i ^ 1]]) a = std::min(a, flow[i]);
            for(i = pre[T]; i != -1; i = pre[v[i ^ 1]])
                flow[i] -= a, flow[i ^ 1] += a;
            c += a * dis[T];
        }
        printf("%d\n", c);
    }
    int main()
    {
        int t;
        scanf("%d", &t);
        while(t --)
        {
            init();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    redis 基本操作-python 使用redis-手机验证接口-发送短信接口
    登录-注册页面修订
    10-29 课堂笔记
    git 协作开发
    git 常规使用
    luffy-city 基础环境搭建(至轮播图前后台交互实现)-步骤目录
    偏移分页-游标(加密)分页-自定义过滤器-第三方过滤器插件(django-filter)
    drf 大总结
    739. Daily Temperatures
    617. Merge Two Binary Trees
  • 原文地址:https://www.cnblogs.com/staginner/p/2641872.html
Copyright © 2011-2022 走看看