POJ 3690 Intervals 费用流 最大变最小

来源:互联网 发布:linux 打包压缩文件夹 编辑:程序博客网 时间:2024/04/30 10:39

题意:给出N个开区间。每个区间有一个权重。问题:让你选出多个区间,最大化总权重,同时,每个点至多被包含k次。

思路:首先,因为区间的个数不多,但是区间的范围比较大,我们要离散化区间端点。接下来的都是对离散化的点进行的操作。

          当K= 1时,这个题等价于从N个区间选出一个元素互不相交的子集。这将变成简单的DP,即01背包问题。

          当K>1时,我们能否贪心的选1次互不相交的区间组成的子集,删掉相应的区间,然后对剩下的区间同样重复处理K次呢?

          实践后发现,这样是不行的,我们仅仅选出了局部最优解,但不是全局最优解。换句话说,我们需要反悔。这个时候是否想到了网络流呢?

          因为要求最大权,我们要用费用流。因为是要求最大费用,而费用流是求最小费用,我们可以利用取负的方法求出最小费用,然后再取负,就是最终的答案。

          我们先整理一下题中给出的条件:1.n个开区间,每个区间有选不选两种选择,选就会有对应的权重。2.每个点至多包含k次。

          所以建图方法如下:

          1.增设源点S,汇点T,S向第一个端点连容量为K,费用为0的边。最后一个端点向T连容量为K,费用为0的边。

          2.每个端点向向后一个端点连费用为0,容量为无穷大的边。

          3.对于每个区间,从左端点向右端点连容量为1,费用为-cost的边。

          然后对整个图跑最小费用流,即可。

代码如下:

#include <cstdio>#include <algorithm>#include <queue>#include <utility>#include <cstring>using namespace std;typedef pair<int,int> pii;template<class T>inline bool read(T &n){T x = 0, tmp = 1; char c = getchar();while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();if (c == EOF) return false;if (c == '-') c = getchar(), tmp = -1;while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar();n = x*tmp;return true;}struct zkw_flow{    static const int MAX = 20000;    static const int INF = 0x3f3f3f3f;    struct edge{        int from,to,cap,flow,cost;        edge(int u=0, int v=0, int c=0, int f=0, int w=0):            from(u),to(v),cap(c),flow(f),cost(w){}    } edges[2 * MAX];    int head[MAX],next[MAX],tot;    int dis[MAX];    bool used[MAX];    int src,sink,n;    int cost,flow;    priority_queue<pii> Q;    void init(int n){        this->n = n;        memset(head,-1,sizeof(head));        tot = 0;    }    void addedge(int u, int v, int c, int w){        edges[tot] = edge(u,v,c,0,w);        next[tot] = head[u], head[u] = tot++;        edges[tot] = edge(v,u,0,0,-w);        next[tot] = head[v], head[v] = tot++;    }    void spfa(){        memset(dis,0x3f,sizeof(dis));        dis[src] = 0; Q.push(make_pair(0,src));        while(!Q.empty()){            pii p = Q.top();Q.pop();            int u = p.second, d = -p.first;            if(dis[u] != d) continue;            for(int v = head[u]; ~v ; v = next[v]){                edge & e = edges[v];                if(e.cap > e.flow && dis[e.to] > d + e.cost){                    dis[e.to] = d + e.cost;                    Q.push(make_pair(-dis[e.to],e.to));                }            }        }        for(int i = 0 ; i < n; ++i)            dis[i] = dis[sink] - dis[i];    }    int augment(int u,int f){        if(u == sink){            flow += f;            cost += dis[src] * f;            return f;        }        used[u] = true;        int now = f;        for(int v = head[u]; ~v; v = next[v]){            edge & e = edges[v];            if(e.cap > e.flow && !used[e.to] &&               dis[u] == dis[e.to] + e.cost){                int tmp = augment(e.to,min(now,e.cap - e.flow));                e.flow += tmp;                edges[v^1].flow -= tmp;                now -= tmp;                if(now == 0) break;            }        }        return f - now;    }    bool modify(){        int d = INF;        for(int u = 0 ; u < n; ++u) if(used[u])            for(int v = head[u]; ~v; v = next[v]){                edge&e = edges[v];                if(e.cap > e.flow && !used[e.to])                    d = min(d, dis[e.to] + e.cost - dis[u]);            }        if(d == INF) return false;        for(int i = 0; i < n; ++i)            if(used[i]) dis[i] += d;        return true;    }    int mincost(int s,int t){        src = s, sink = t;        flow = cost = 0;        spfa();        for(;;){            for(;;){                memset(used,0,sizeof(used));                if(!augment(src,INF)) break;            }            if(!modify()) break;        }        return cost;    }} solver;const int MAX = 200;const int INF = 0x3f3f3f3f;int T,K,N;int a[MAX],b[MAX],w[MAX];int main(void){    //freopen("input.txt","r",stdin);    read(T);    while(T--){        read(N),read(K);        vector<int> x;        for(int i = 0 ; i < N; ++i){            read(a[i]),read(b[i]),read(w[i]);            x.push_back(a[i]);            x.push_back(b[i]);        }        sort(x.begin(),x.end());        x.erase(unique(x.begin(),x.end()),x.end());        int m = x.size();        int s = m, t = s + 1;        solver.init(m + 2);        int res = 0;        solver.addedge(s,0,K,0);        solver.addedge(m-1,t,K,0);        for(int i = 0 ; i + 1 < m; ++i)            solver.addedge(i,i+1,INF,0);        for(int i = 0 ; i < N; ++i){            int u = lower_bound(x.begin(),x.end(),a[i]) - x.begin();            int v = lower_bound(x.begin(),x.end(),b[i]) - x.begin();            solver.addedge(u,v,1,-w[i]);        }        printf("%d\n",-solver.mincost(s,t));    }    return 0;}


0 0
原创粉丝点击