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个数的下标,现在作为图中该数的节点编号,假设是从i连一条弧线出来,起点是i,终点是j,费用为i这个点的数值。j应该是多少呢?
区间为[i,i+m-1],经过从i为起点连的弧线表示选了下标为i的这个数。如果j仍然在[i,i+m-1]这个区间范围内,那么流过i->j这条弧线得流量还可以从[i,i+m-1]的另一个点k作为起点
流出来,又会把下标为k的数值计算进去。而流量为1表示该全区间选了一个数,而这里显然一个流量为1,贡献了不止一个数。可能选择更多的数。
所以j=i+m; 记住!一个流量保证在同一个区间只贡献一次。该流量可以继续流到别的区间继续贡献。这就是为什么起点s->1,cap = k;表示最多k个流量,那么一个区间最多选k个数。

建图:原来的n个数的数值为w1~wn.
s->1,cap=k,cost=0;
1->2,cap=INF,cost=0;
2->3..
..
..
..
n-1->n,cap=INF,cost=0;
n->t (t=n+1) cap=k,cost=0;

然后枚举1到n;
i->min(i+m,t), cap=1, cost = -w[i];

求s->t最小费用最大流。

*/
#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 = 1010;
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 w[N];
int main()
{
    int n, m, k;
    while(scanf("%d%d%d",&n,&m,&k)==3)
    {
        for(int i = 1; i <= n; i++) scanf("%d",&w[i]);

        int s = 0, t = n+1;
        MCMF mcmf;
        mcmf.init(t);
        mcmf.AddEdge(s,1,k,0);
        for(int i = 1; i < t; i++){
            mcmf.AddEdge(i,i+1,INF,0);
        }
        for(int i = 1; i <=n; i++){
            int u = i, v = min(t,i+m);
            mcmf.AddEdge(u,v,1,-w[i]);
        }
        LL cost;
        mcmf.MincostMaxflow(s,t,cost);
        printf("%lld\n",-cost);
    }
    return 0;
}
时间: 2024-10-13 03:08:48

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

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->

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)表示流量

HDU5900 QSC and Master(区间DP + 最小费用最大流)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, Northeastern University is the same. Enter from the north gate of Northeastern University,You are facing the main building of Northeastern University.

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

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

HDU 3488--Tour【最小费用最大流 &amp;&amp; 有向环最小权值覆盖 &amp;&amp; 经典】

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 1156 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 3000

HDU 1853--Cyclic Tour【最小费用最大流 &amp;&amp; 有向环最小权值覆盖 】

Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1950    Accepted Submission(s): 984 Problem Description There are N cities in our country, and M one-way roads connecting them. Now L

连续最短路算法(Successive Shortest Path)(最小费用最大流)

1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 #define N 205 8 #define INF 0x3f3f3f3f 9 struct node { 10 int x, y; 11 node () {} 12 node (int x,

HDU 3572 【最大流 &amp;&amp; 时间区间建图】

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5398    Accepted Submission(s): 1742 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

位操作(求[a, b] 中二进制位为1的个数最多的数)

传送门 题意:求区间[a, b]中二进制位为1的个数最多的那个数,如果存在多解,则输出最小的那个.(0 <= a <= b) 关键: 对一个数a可以利用 a | (a + 1) 来将a的二进制位中最低的0设置为1 附上代码: 1 #include <stdio.h> 2 3 typedef long long ll; 4 5 int main(void) { 6 int n; 7 scanf("%d", &n); 8 while (n-- > 0)