poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙

/**
题目:poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙
链接:http://poj.org/problem?id=3680
题意:给定n个区间,每个区间(ai,bi),以及权值wi。选出一些区间,满足权值和最大且任何一个点不会被超过k个区间覆盖。
思路:
建图:对于每个区间(ai,bi)。 ai->bi,cap = 1,cost = -wi; (离散化后的ai,bi)
所有区间的端点放到数组,进行从小到大排序,去重,离散化,在数组内相邻的u端点,v端点。u->v,cap = INF,cost=0;
s->x最左边的那个端点(也就是离散化后最小的那个数),cap = k, cost = 0;
x(最右边的那个端点)->t,cap = k, cost = 0;
求s->t的最小费用最大流,输出-cost即为结果。

可以把图想象成一个x轴上有若干端点,(ai,bi)上面连了一条弧线。从最左边开始跑,到最右边,如果最左边cap=k。
那么最多k流量往右边流,每个点最多被k流量覆盖,每一个单位流量分配给一个区间(ai,bi),所以最多被k个区间覆盖。

*/

#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<sstream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 420;
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}
};
struct MCMF{
    int n, m;
    vector<Edge> edges;
    vector<int> G[N];
    int inq[N];
    int d[N];
    int p[N];
    int a[N];

    void init(int n){
        this->n = n;
        for(int i = 0; i <= n; i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int cap,long long cost){
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BellmanFord(int s,int t,int &flow,long long &cost){
        for(int i = 0; i <= n; i++) d[i] = INF;
        memset(inq, 0, sizeof inq);
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

        queue<int>  Q;
        Q.push(s);
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            inq[u] = 0;
            for(int i = 0; i < G[u].size(); i++){
                Edge& e = edges[G[u][i]];
                if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
                    d[e.to] = d[u]+e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u],e.cap-e.flow);
                    if(!inq[e.to]) {Q.push(e.to); inq[e.to] = 1;}
                }
            }
        }
        if(d[t]==INF) return false;
        flow += a[t];
        cost += (long long)d[t]*(long long)a[t];
        for(int u = t; u!=s; u = edges[p[u]].from){
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }
    int MincostMaxflow(int s,int t,long long &cost){
        int flow = 0;
        cost = 0;
        while(BellmanFord(s,t,flow,cost));
        return flow;
    }
};
int u[N], v[N], w[N];
vector<int> vv;
map<int,int> mp;
int main()
{
    int T, n, k;
    cin>>T;
    while(T--)
    {
        int s = 0, t;
        scanf("%d%d",&n,&k);
        vv.clear();
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            vv.push_back(u[i]);
            vv.push_back(v[i]);
        }
        sort(vv.begin(),vv.end());
        vv.erase(unique(vv.begin(),vv.end()),vv.end());///相邻重复元素,多余出来的全部放到后面,并返回一个开始指针
        mp.clear();
        for(int i = 0; i < vv.size(); i++){
            mp[vv[i]] = i+1;
        }
        t = vv.size()+1;
        MCMF mcmf;
        mcmf.init(t);
        mcmf.AddEdge(s,1,k,0);
        mcmf.AddEdge(vv.size(),t,k,0);
        for(int i = 1; i < vv.size(); i++){
            mcmf.AddEdge(i,i+1,INF,0);
        }
        for(int i = 1; i <= n; i++){
            mcmf.AddEdge(mp[u[i]],mp[v[i]],1,-w[i]);
        }
        LL cost;
        int flow = mcmf.MincostMaxflow(s,t,cost);
        printf("%lld\n",-cost);
    }
    return 0;
}
时间: 2024-10-13 08:22:09

poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙的相关文章

hdu4106 区间k覆盖问题(连续m个数,最多选k个数) 最小费用最大流 建图巧妙

/** 题目:hdu4106 区间k覆盖问题(连续m个数,最多选k个数) 最小费用最大流 建图巧妙 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4106 题意:给你n个数,每连续m个数,最多选k个数,问可以选的数的权值和最大多少. 思路:可以转化为区间k覆盖问题.区间k覆盖问题是每个点最多被k个区间覆盖.本题是每个区间最多选k个点. 刚好相反.我的做法有点不同其他博客那种做法.当然本质一样. 我这里的i就是原来n个数的下标,现在作为图中该数的节点编号

ZOJ 3885--The Exchange of Items【最小费用最大流 &amp;&amp; 建图】

The Exchange of Items Time Limit: 2 Seconds      Memory Limit: 65536 KB Bob lives in an ancient village, where transactions are done by one item exchange with another. Bob is very clever and he knows what items will become more valuable later on. So,

网络流最小费用最大流建图些许方法

无向图的情况 加边的时候直接加两条边即可,因为这个dinic算法是可以判重边 poj 3469 代码 最小流 流量确定的时候 添加两个源点和汇点 前两个源点相连,汇点相连,容量为确定的流量 poj 2135 代码 poj 3686 代码 多源多汇 添加一个源点和汇点 把源点和每一个之前的相连 容量为1 把汇点和每一个之前的相连 容量为1 poj 3281 代码 poj 2195 代码 版权声明:都是兄弟,请随意转载,请注明兄弟是谁

HDU 4862 Jump (2014-多校1-1002,最小K路径覆盖,最小费用最大流)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=4862 题意: 给你一个n*m的矩阵,填充着0-9的数字,每次能从一个点出发,到它的右边或者下边的点,花费为|x1-x2|+|y1-y2|-1,如果跳跃的起点和终点的数字相同,则获得这个数字的收益,不能走已经走过的点 有K次重新选择起点的机会 如果可以走遍所有点,则输出最大的价值(收益-花费) 否则,输出-1 方法: 最小K路径覆盖,最小费用最大流 建图: 每个点拆为2点:X部和Y部,(a,b)表示流量

POJ 2516 跑k次的最小费用最大流

题目大意:给出n个客户对k个商品的需求量,又给出m个仓库对k个物品的存货量以及对k个物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费,是典型的最小费用最大流! 思路:可以将k中物品分开求最小费用最大流,然后想加得到总的最小费用最大流! 建图,对每个仓库是一个结点,每个客户也是一个结点,除此之外再加上s源点和t结束点! 1.s到仓库i的边的流量为仓库i的供给量,费用没有当然为0: 2.仓库i到客户j的流量为仓库的供给量,费用为仓库i到客户j的运输

poj3422 拆点法x-&gt;x&#39;建立两条边+最小费用最大流

/** 题目:poj3422 拆点法+最小费用最大流 链接:http://poj.org/problem?id=3422 题意:给定n*n的矩阵,含有元素值,初始sum=0.每次从最左上角开始出发,每次向右或者向下一格.终点是右下角. 每经过一个格子,获取它的值,并把该格子的值变成0.问经过k次从左上角到右下角.能得到的数值和最大多少. 思路:我觉得本题元素值全是非负数.要不然不可以过.很多网上的博客代码在有负数情况下过不了. 拆点法+最小费用最大流 建图: 每一个格子x,拆成x,xi, x向x

ACM-ICPC 2018 焦作赛区网络预赛 F. Modular Production Line (区间K覆盖-最小费用流)

很明显的区间K覆盖模型,用费用流求解.只是这题N可达1e5,需要将点离散化. 建模方式步骤: 1.对权值为w的区间[u,v],加边id(u)->id(v+1),容量为1,费用为-w; 2.对所有相邻的点加边id(i)->id(i+1),容量为正无穷,费用为0; 3.建立源点汇点,由源点s向最左侧的点加边,容量为K,费用为0,由最右侧的点向汇点加边,容量为K,费用为0 4.跑出最大流后,最小费用取绝对值就是能获得的最大权 #include<bits/stdc++.h> using n

POJ2047 Concert Hall Scheduling(最小费用最大流)

题目大概是有两个音乐厅,有n个乐队申请音乐厅,他们必须从第ii天到第ji天连续开音乐会且他们的开价是wi,每天每个音乐厅都只能供一个乐队进行音乐会.问接受哪些乐队的申请,获利最多能多少. 这题相当于在一条数轴上选择最大权和的线段,使两两相交的线段不超过两个.POJ3680,区间k覆盖. 先把每个申请的时间段处理成左闭右开的区间,然后离散化,建容量网络,跑MCMF即可. 1 #include<cstdio> 2 #include<cstring> 3 #include<queu

POJ3680 Intervals(最小费用最大流)

选择若干条线段使权值最大,并且点覆盖次数不超过k. 建图如下:vs到0建立容量为k费用为0的边:坐标终点到vt连接一条容量为k费用为0的边:对于每两个相邻坐标连接一条容量为INF费用为0的边:对于线段每两个端点连接一条容量1费用为-cost的边. 这样跑最小费用最大流.相当于找出k个线段集合,每个集合的线段都不重合.原问题就这样求解. 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include&