\(\mathcal{Description}\)

  Link.

  在一个 \(n\times n\) 的方格图中,有一些格子已经放了零件,有一些格子可以放零件,其余格子不能放零件。求至多放多少个零件,满足第 \(i\) 行与第 \(i\) 列中零件个数相等;任意一行或一列的零件数量不超过总数量的 \(\frac{A}{B}\)。\(n\le40\)。

\(\mathcal{Solution}\)

  能猜测是行列连边的二分图网络模型,但注意到网络流很难处理 \(\frac{A}{B}\) 这个比较“全局性”的限制,这提示我们可以直接枚举行列个数上限 \(x\),若能求出在此上限下最多放置的零件个数就能判断是否合法了。

  进一步,对于每个方格“放不放零件”这一问题,在网络中必须保证只有两种状态。即,每个方格都明确“放”还是“不放”。黑白染色的最小割在这里不使用,我们转而考虑用“流最大”来限制每个方格都明确选择,用网络流的另一个维度——费用,来得到答案最大。

  我已经尽力描述这题的 motivation 了 qwq,接下来直接给出建图模型:

  • \(S\) 连向行点 \(r_i\),流量为第 \(i\) 行已放和能放的零件数量,费用为 \(0\);

  • \(r_i\) 连向列点 \(c_i\),流量为枚举的 \(x\),费用为 \(0\);

  • \(c_i\) 连向 \(T\),流量为第 \(i\) 列已放和能放的零件数量,费用为 \(0\);

  • 对于能放但未放的格子 \((i,j)\),连接 \(r_i,c_j\),流量为 \(1\),费用为 \(1\)。

  注意把“放的最大”转为“不放的最小”,再用最小费用流。

\(\mathcal{Code}\)

  1. /*+Rainybunny+*/
  2. #include <bits/stdc++.h>
  3. #define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
  4. #define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
  5. typedef std::pair<int, int> PII;
  6. #define fi first
  7. #define se second
  8. inline int imax(const int u, const int v) { return u < v ? v : u; }
  9. inline int imin(const int u, const int v) { return u < v ? u : v; }
  10. const int MAXN = 40, IINF = 0x3f3f3f3f;
  11. int n, A, B, row[MAXN + 5], col[MAXN + 5];
  12. char str[MAXN + 5][MAXN + 5];
  13. namespace CFG { // cost flow graph.
  14. const int MAXND = MAXN * 2 + 2, MAXEG = MAXN * (MAXN + 3);
  15. int S, T, ecnt = 1, head[MAXND + 5], curh[MAXND + 5];
  16. int dis[MAXND + 5], hig[MAXND + 5];
  17. bool instk[MAXND + 5];
  18. struct Edge { int to, flw, cst, nxt; } graph[MAXEG * 2 + 5];
  19. inline void clear() {
  20. ecnt = 1;
  21. rep (i, S, T) head[i] = hig[i] = dis[i] = instk[i] = 0;
  22. }
  23. inline void link(const int s, const int t, const int f, const int c) {
  24. // printf("%d %d %d %d\n", s, t, f, c);
  25. graph[++ecnt] = { t, f, c, head[s] }, head[s] = ecnt;
  26. graph[++ecnt] = { s, 0, -c, head[t] }, head[t] = ecnt;
  27. }
  28. inline bool dijkstra() {
  29. static std::priority_queue<PII, std::vector<PII>, std::greater<PII> > heap;
  30. rep (i, S, T) hig[i] += dis[i], dis[i] = IINF;
  31. heap.push({ dis[S] = 0, S });
  32. while (!heap.empty()) {
  33. PII p(heap.top()); heap.pop();
  34. if (dis[p.se] != p.fi) continue;
  35. for (int i = head[p.se], v; i; i = graph[i].nxt) {
  36. int d = p.fi + graph[i].cst + hig[p.se] - hig[v = graph[i].to];
  37. assert(!graph[i].flw || graph[i].cst + hig[p.se] - hig[v] >= 0);
  38. if (graph[i].flw && dis[v] > d) heap.push({ dis[v] = d, v });
  39. }
  40. }
  41. return dis[T] != IINF;
  42. }
  43. inline PII augment(const int u, int iflw) {
  44. if (u == T) return { iflw, 0 };
  45. PII ret(0, 0); instk[u] = true;
  46. for (int &i = curh[u], v; i; i = graph[i].nxt) {
  47. if (graph[i].flw && !instk[v = graph[i].to]
  48. && dis[v] == dis[u] + hig[u] - hig[v] + graph[i].cst) {
  49. PII tmp(augment(v, imin(iflw, graph[i].flw)));
  50. ret.fi += tmp.fi, ret.se += graph[i].cst * tmp.fi + tmp.se;
  51. iflw -= tmp.fi, graph[i].flw -= tmp.fi, graph[i ^ 1].flw += tmp.fi;
  52. if (!iflw) break;
  53. }
  54. }
  55. if (ret.fi) instk[u] = false;
  56. return ret;
  57. }
  58. inline PII dinic() {
  59. PII ret(0, 0);
  60. while (dijkstra()) {
  61. rep (i, S, T) curh[i] = head[i], instk[i] = false;
  62. PII tmp(augment(S, IINF));
  63. ret.fi += tmp.fi, ret.se += tmp.se;
  64. }
  65. return ret;
  66. }
  67. } // namespace CFG.
  68. int main() {
  69. while (~scanf("%d %d %d", &n, &A, &B) && n | A | B) {
  70. static int cas = 0; printf("Case %d: ", ++cas);
  71. rep (i, 1, n) scanf("%s", str[i] + 1), row[i] = col[i] = 0;
  72. int all = 0, own = 0;
  73. rep (i, 1, n) rep (j, 1, n) {
  74. bool f = str[i][j] == '.' || str[i][j] == 'C';
  75. row[i] += f, col[j] += f, all += f, own += str[i][j] == 'C';
  76. }
  77. int ans = -1;
  78. rep (x, 0, n) {
  79. CFG::S = 0, CFG::T = n << 1 | 1, CFG::clear();
  80. rep (i, 1, n) {
  81. CFG::link(CFG::S, i, row[i], 0);
  82. CFG::link(i + n, CFG::T, col[i], 0);
  83. CFG::link(i, i + n, x, 0);
  84. }
  85. rep (i, 1, n) rep (j, 1, n) if (str[i][j] == '.') {
  86. CFG::link(i, j + n, 1, 1);
  87. }
  88. PII res(CFG::dinic());
  89. // printf("%d: %d %d\n", x, res.fi, res.se);
  90. if (res.fi == all && (all - res.se) * A >= x * B) {
  91. ans = imax(ans, all - res.se);
  92. }
  93. }
  94. if (~ans) printf("%d\n", ans - own);
  95. else puts("impossible");
  96. }
  97. return 0;
  98. }

Solution -「UVA 1104」Chips Challenge的更多相关文章

  1. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  2. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  3. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

  4. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  5. Solution -「简单 DP」zxy 讲课记实

    魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...

  6. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  7. Solution -「WC 2022」秃子酋长

    \(\mathscr{Description}\)   Link. (It's empty temporarily.)   给定排列 \(\{a_n\}\),\(q\) 次询问,每次给出 \([l,r ...

  8. Solution -「JSOI 2019」「洛谷 P5334」节日庆典

    \(\mathscr{Description}\)   Link.   给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的).   \(|S|\le3\time ...

  9. Solution -「CF 1622F」Quadratic Set

    \(\mathscr{Description}\)   Link.   求 \(S\subseteq\{1,2,\dots,n\}\),使得 \(\prod_{i\in S}i\) 是完全平方数,并最 ...

随机推荐

  1. koa路由接口

    const router = require('koa-router')() //返回一个页面 router.get('/', async (ctx, next) => { global.con ...

  2. h5跳转高德地图

    <a href="https://uri.amap.com/marker?position=经度,纬度&name=所在的位置名称">高德地图</a>

  3. SCALA-基础知识学习(一)

    概述 本人开始学习scala的时候,是在使用和开发spark程序的时候,在此为了整理.记录和分享scala的基础知识,我写这篇关于scala的基础知识,希望与广大读者共同学习沟通进步.如果有些代码比较 ...

  4. 使用.NET 6开发TodoList应用(26)——实现Configuration和Option的强类型绑定

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在上一篇文章使用.NET 6开发TodoList应用(25)--实现RefreshToken中,我们通过使用Configura ...

  5. Java 各个版本中的新特性

    新特性你知道多少? Java 8 Lambda 表达式 接口增加默认方法等 方法引用 流 Stream Java 9 模块系统 交互式工具jshell .of() 创建不可变集合 接口支持私有方法 更 ...

  6. PWA 技术落地!让你的站点(Web)秒变APP(应用程序)

    Web应用方兴未艾,我们已经十分习惯习惯了在电脑上进行以自己的工作,而随着众多功能强大的在线网站,我们的Windows的桌面也不再拥挤着各种快捷方式:不光是PC端,在移动端我们也不再在浩如烟海的应用市 ...

  7. Python 根据id生成唯一码

    Python 根据id生成唯一码 最近业务中遇到需要分享某个文案,复制文案打开APP需要提取文案中包含的id,但又不想明文暴露id,所以需要对id进行加密,很想让前端来做,可惜多个前端协调起来不方便( ...

  8. 关于C++11共享数据带来的死锁问题的提出与解决

    举个例子,如果有一份资源,假如为list<int>资源,假设有两个线程要对该资源进行压入弹出操作,如果不进行锁的话,那么如果两个线程同时操作,那么必然乱套,得到的结果肯定不是我们想要的结果 ...

  9. QT之事件机制

    MyPushButton.h: #ifndef MYPUSHBUTTON_H #define MYPUSHBUTTON_H #include<QPushButton> #include&l ...

  10. gin中的文件上传

    1. 单文件上传 package main import ( "fmt" "github.com/gin-gonic/gin" "log" ...