首页 > 其他分享 >UVA11613 Acme Corporation

UVA11613 Acme Corporation

时间:2023-03-09 22:45:51浏览次数:40  
标签:std Acme int Corporation UVA11613 i64 vis cost dis

UVA11613 Acme Corporation

题意

翻译已经很清楚了。

思路

看到这种求限制下的最值的问题,而且数据范围还比较小,我们不难想到费用流。但是这道题要求的是最大利润,那么我们可以将边权全部乘以 \(-1\),这样就可以通过求最小费用来求得最大利润。此时我们求的也就是亏钱的最小值,只不过这个值可以是负的,表示盈利。

为了方便,我们约定源点为 \(s\),汇点为 \(t\)。

首先,我们可以将第 \(i\) 个月拆成两个点:\(i\) 和 \(i + N\),其中我们用 \(i\) 来表示成本,\(i + N\) 来表示销售额。然后从 \(s\) 向 \(i\) 引一条容量为 \(n_i\),费用为 \(m_i\) 的边,表示该月能够生产 \(n_i\) 件物品,每一件的成本为 \(m_i\)。再从 \(i + N\) 向 \(t\) 引一条容量为 \(s_i\),费用为 \(-p_i\) 的边,表示该月能够出售 \(s_i\) 件物品,每一件的售价为 \(p_i\)。

然后我们再来处理储存物品的问题。对于每一个 \(j \in [0, e_i]\),我们从 \(i\) 向 \(i + j + N\) 引一条边,其容量为 \(+\inf\),费用为 \(W \times j\),表示第 \(i\) 个月能够以 \(W \times j\) 的代价将物品储存至第 \(i + j\) 个月。其实这里边的容量取 \(n_i\) 就可以了,但是为了方便,我取了正无穷。

然后这张图就建好了。可以看出这张图是不可能存在负环的,那么我们将边权取相反数的做法就没有问题。

但是此时还有一个问题:每个月不一定非得生产 \(n_i\) 件物品,也就是说当利润最大时,对应的流可以不是满流。那么这个问题也就不是普通的 MCMF 问题,而是最大费用任意流问题。

处理方法也很简单,对于普通的连续最短路 MCMF,我们只需做这么一个变动:如果此次增广的费用为正,也就是亏了钱时,我们直接 break 就好了,因为此时你无论再怎么增广,费用都始终为正,也就是不可能再赚钱的。

代码

/**
 * @file    UVA11613 Acme Corporation.cpp
 * @author  ForgotDream
 * @brief   最大费用任意流
 * @date    2023-03-09
 */
#include <bits/stdc++.h>

using i64 = long long;

static const int INF = 0x3f3f3f3f;
struct MCMF {
  struct Edge {
    int from, to;
    i64 cap, cost;
    Edge(int u, int v, i64 cap, i64 cost) 
      : from(u), to(v), cap(cap), cost(cost) {}
  };
  static const i64 INF = 1e18;
  int n, s, t;
  std::vector<Edge> edge;
  std::vector<std::vector<int>> e;
  std::vector<int> cur;
  std::vector<i64> dis;
  std::vector<bool> vis;
  
  MCMF(const int &n) {
    this->n = n;
    e.resize(n);
    cur.resize(n);
    dis.resize(n);
    vis.resize(n);
    return;
  }

  bool spfa(int s, int t) {
    std::fill(dis.begin(), dis.end(), INF);
    std::fill(vis.begin(), vis.end(), false);
    std::fill(cur.begin(), cur.end(), 0);
    std::queue<int> q;

    q.push(s);
    dis[s] = 0;
    vis[s] = true;

    while (!q.empty()) {
      int u = q.front();
      q.pop();
      vis[u] = false;
      for (int i : e[u]) {
        int v = edge[i].to;
        if (edge[i].cap && dis[v] > dis[u] + edge[i].cost) {
          dis[v] = dis[u] + edge[i].cost;
          if (!vis[v]) {
            vis[v] = true;
            q.push(v);
          }
        }
      }
    }

    return dis[t] != INF;
  }

  i64 dfs(int u, i64 flow, i64 &minCost) {
    if (u == t || flow == 0) {
      return flow;
    }
    i64 res = 0, tmp;
    vis[u] = true;
    for (int &i = cur[u]; i < e[u].size(); i++) {
      Edge &curEdge = edge[e[u][i]];
      if (!vis[curEdge.to] && dis[curEdge.to] == dis[u] + curEdge.cost && 
          (tmp = dfs(curEdge.to, std::min(curEdge.cap, flow), minCost)) > 0) {
        minCost += tmp * curEdge.cost;
        curEdge.cap -= tmp;
        edge[e[u][i] ^ 1].cap += tmp;
        res += tmp;
        flow -= tmp;
        if (flow == 0) {
          break;
        }
      }
    }
    vis[u] = false;
    return res;
  }

  void add(int u, int v, i64 cap, i64 cost) {
    edge.emplace_back(u, v, cap, cost);
    edge.emplace_back(v, u, 0, -1 * cost);

    e[u].push_back(edge.size() - 2);
    e[v].push_back(edge.size() - 1);

    return;
  }

  std::pair<int, i64> solve(int s, int t) {
    int flow = 0;
    i64 cost = 0, lst = 0;
    this->s = s;
    this->t = t;
    while (spfa(s, t)) {
      lst = cost;
      flow += dfs(s, INF, cost);
      if (cost > lst) {
        break;
      }
    }
    return std::make_pair(flow, lst);
  }
};

void solve(int no) {
  int N;
  i64 W;
  std::cin >> N >> W;
  MCMF solver(2 * N + 50);
  int S = 0, T = 2 * N + 1;
  for (int i = 1; i <= N; i++) {
    i64 m, p;
    int n, s, e;
    std::cin >> m >> n >> p >> s >> e;
    for (int j = 0; i + j <= N && j <= e; j++) {
      solver.add(i, i + j + N, INF, W * j);
    }
    solver.add(S, i, n, m);
    solver.add(i + N, T, s, -1 * p);
  }
  std::cout << "Case " << no << ": " << -1 * solver.solve(S, T).second << "\n";
  return;
}

signed main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  
  int t;
  std::cin >> t;

  for (int i = 1; i <= t; i++) {
    solve(i);
  }

  return 0;
}

标签:std,Acme,int,Corporation,UVA11613,i64,vis,cost,dis
From: https://www.cnblogs.com/forgot-dream/p/17201757.html

相关文章

  • Acme CAD Converter版本转换器下载地址+使用教程
    AcmeCADConverter下载地址网盘地址 AcmeCADConverter使用教程第一步:下载压缩包,打开图示软件; 第二步:把图纸直接拖进软件中,另存为低版本即可。 ......
  • HUEL日常感悟(算是一枚菜鸡ACMer的小日记吧)
    2020/7/17 郑州雨最近跟hky进行暑期联谊集训,已经进行了半个月吧,大一的生活就这么在疫情中结束,截至今天vj上已经solved了745道题,不是说千题之后ACM就会比较轻松了嘛,为什......
  • ACMer反思
       不知不觉ACM已经训练了大半年了,但是一直没出成绩,最近两场比赛也打击很大,一个小小的青岛理工大学的比赛都没能拿着牌,还有秦皇岛ccpc的那场比赛c题应该是能出的,结果也......
  • 使用Acme.sh免费签发SSL证书
    github:​​https://github.com/acmesh-official/acme.sh​​ 概述一个纯粹用Shell(Unixshell)语言编写的ACME协议客户端。完整的ACME协议实施。支持ACMEv1和ACMEv2支持......
  • ACME:通过DNS方式添加证书
    在通常情况下,用DNSAPI方式自动注册证书是最好的方式,但是如果域名服务商不支持API方式,然后又想注册泛域名的话,就只能通过DNS手动方式来操作。首先第一步,调用issue参数来......
  • 一个新ACMer的刷题记录捏(Round.694) codeforces ABC
    A.StrangePartitionProblem-A-Codeforces  2022-12-1514:00:52​#include<bits/stdc++.h>#defineintlonglongconstintN=100010;usingnamespac......
  • 用acme.sh自动部署域名证书
    用acme.sh自动部署域名证书安装ACME目前使用量最大的免费SSL证书就是Let’sEncrypt,自2018-03开始,Let’sEncrypt官方发布上线了免费的SSL泛域名证书,目前通过DNS方式获取......
  • Let’s Encrypt Challenge and acme.sh Issue Mode
    Basicdnscname:将域名指向另外一个域名;txt:存储一个512长度内的文本,通常作SPF记录(SenderPolicyFramework反垃圾邮件);ns:将子域名指定其他的DNS服务器解析;dig​​linuxd......
  • 使用Acme.sh免费签发SSL证书
    github:https://github.com/acmesh-official/acme.sh 概述一个纯粹用Shell(Unixshell)语言编写的ACME协议客户端。完整的ACME协议实施。支持ACMEv1和ACMEv2支持ACME......
  • 使用acme.sh自助签发Let's Encrypt 的SSL证书
    文档说明:只记录关键地方;Let’sEncrypt是一个证书颁发机构(CA)试验环境:linuxdebian11docker目标:自助签发域名SSL证书(包括通配符证书)容器运行acme.shversion......