Solution -「UVA 1104」Chips Challenge
\(\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}\)
/*+Rainybunny+*/
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
typedef std::pair<int, int> PII;
#define fi first
#define se second
inline int imax(const int u, const int v) { return u < v ? v : u; }
inline int imin(const int u, const int v) { return u < v ? u : v; }
const int MAXN = 40, IINF = 0x3f3f3f3f;
int n, A, B, row[MAXN + 5], col[MAXN + 5];
char str[MAXN + 5][MAXN + 5];
namespace CFG { // cost flow graph.
const int MAXND = MAXN * 2 + 2, MAXEG = MAXN * (MAXN + 3);
int S, T, ecnt = 1, head[MAXND + 5], curh[MAXND + 5];
int dis[MAXND + 5], hig[MAXND + 5];
bool instk[MAXND + 5];
struct Edge { int to, flw, cst, nxt; } graph[MAXEG * 2 + 5];
inline void clear() {
    ecnt = 1;
    rep (i, S, T) head[i] = hig[i] = dis[i] = instk[i] = 0;
}
inline void link(const int s, const int t, const int f, const int c) {
    // printf("%d %d %d %d\n", s, t, f, c);
    graph[++ecnt] = { t, f, c, head[s] }, head[s] = ecnt;
    graph[++ecnt] = { s, 0, -c, head[t] }, head[t] = ecnt;
}
inline bool dijkstra() {
    static std::priority_queue<PII, std::vector<PII>, std::greater<PII> > heap;
    rep (i, S, T) hig[i] += dis[i], dis[i] = IINF;
    heap.push({ dis[S] = 0, S });
    while (!heap.empty()) {
        PII p(heap.top()); heap.pop();
        if (dis[p.se] != p.fi) continue;
        for (int i = head[p.se], v; i; i = graph[i].nxt) {
            int d = p.fi + graph[i].cst + hig[p.se] - hig[v = graph[i].to];
            assert(!graph[i].flw || graph[i].cst + hig[p.se] - hig[v] >= 0);
            if (graph[i].flw && dis[v] > d) heap.push({ dis[v] = d, v });
        }
    }
    return dis[T] != IINF;
}
inline PII augment(const int u, int iflw) {
    if (u == T) return { iflw, 0 };
    PII ret(0, 0); instk[u] = true;
    for (int &i = curh[u], v; i; i = graph[i].nxt) {
        if (graph[i].flw && !instk[v = graph[i].to]
          && dis[v] == dis[u] + hig[u] - hig[v] + graph[i].cst) {
            PII tmp(augment(v, imin(iflw, graph[i].flw)));
            ret.fi += tmp.fi, ret.se += graph[i].cst * tmp.fi + tmp.se;
            iflw -= tmp.fi, graph[i].flw -= tmp.fi, graph[i ^ 1].flw += tmp.fi;
            if (!iflw) break;
        }
    }
    if (ret.fi) instk[u] = false;
    return ret;
}
inline PII dinic() {
    PII ret(0, 0);
    while (dijkstra()) {
        rep (i, S, T) curh[i] = head[i], instk[i] = false;
        PII tmp(augment(S, IINF));
        ret.fi += tmp.fi, ret.se += tmp.se;
    }
    return ret;
}
} // namespace CFG.
int main() {
    while (~scanf("%d %d %d", &n, &A, &B) && n | A | B) {
        static int cas = 0; printf("Case %d: ", ++cas);
        rep (i, 1, n) scanf("%s", str[i] + 1), row[i] = col[i] = 0;
        int all = 0, own = 0;
        rep (i, 1, n) rep (j, 1, n) {
            bool f = str[i][j] == '.' || str[i][j] == 'C';
            row[i] += f, col[j] += f, all += f, own += str[i][j] == 'C';
        }
        int ans = -1;
        rep (x, 0, n) {
            CFG::S = 0, CFG::T = n << 1 | 1, CFG::clear();
            rep (i, 1, n) {
                CFG::link(CFG::S, i, row[i], 0);
                CFG::link(i + n, CFG::T, col[i], 0);
                CFG::link(i, i + n, x, 0);
            }
            rep (i, 1, n) rep (j, 1, n) if (str[i][j] == '.') {
                CFG::link(i, j + n, 1, 1);
            }
            PII res(CFG::dinic());
            // printf("%d: %d %d\n", x, res.fi, res.se);
            if (res.fi == all && (all - res.se) * A >= x * B) {
                ans = imax(ans, all - res.se);
            }
        }
        if (~ans) printf("%d\n", ans - own);
        else puts("impossible");
    }
    return 0;
}
Solution -「UVA 1104」Chips Challenge的更多相关文章
- Solution -「ARC 104E」Random LIS
		\(\mathcal{Description}\) Link. 给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ... 
- Solution -「CTS 2019」「洛谷 P5404」氪金手游
		\(\mathcal{Description}\) Link. 有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ... 
- Solution -「BZOJ 3812」主旋律
		\(\mathcal{Description}\) Link. 给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ... 
- Solution -「CF 1342E」Placing Rooks
		\(\mathcal{Description}\) Link. 在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ... 
- Solution -「简单 DP」zxy 讲课记实
		魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ... 
- Solution -「基环树」做题记录
		写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ... 
- Solution -「WC 2022」秃子酋长
		\(\mathscr{Description}\) Link. (It's empty temporarily.) 给定排列 \(\{a_n\}\),\(q\) 次询问,每次给出 \([l,r ... 
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
		\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ... 
- Solution -「CF 1622F」Quadratic Set
		\(\mathscr{Description}\) Link. 求 \(S\subseteq\{1,2,\dots,n\}\),使得 \(\prod_{i\in S}i\) 是完全平方数,并最 ... 
随机推荐
- C# string.Format 和 String.Format 的区别
			string.Format 和 String.Format ,不论是用法还是意思,都是一样的 怎么使用? 通过 占位符来替换 ,类似于 Replace 的操作 string s = string.F ... 
- spring security 继承 WebSecurityConfigurerAdapter 的重写方法configure() 参数  HttpSecurity 常用方法及说明
			HttpSecurity 常用方法及说明 方法 说明 openidLogin() 用于基于 OpenId 的验证 headers() 将安全标头添加到响应 cors() 配置跨域资源共享( CORS ... 
- js知识框架图
- Linux上天之路(二)之Linux安装
			1. vmware workstation使用 VMware是全球领先的虚拟化公司,为客户提供虚拟化解决方案,个人虚拟化产品workstation,可以让用户通过虚拟化的方式在一台物理电脑中安装多个操 ... 
- JAVA之垃圾收集器
			概述 垃 圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计 ... 
- jsp标签问题
			在jsp页面使用标签过程中有时候不注意规则的话,eclipse会提示一些错误,下面针对这些错误提出相应的解决办法:<form></form>标签1. Invalid locat ... 
- ipython notebook教程
			一.简介 Jupyter Notebook是一个开源的Web应用程序,允许用户创建和共享包含代码.方程式.可视化和文本的文档.它的用途包括:数据清理和转换.数值模拟.统计建模.数据可视化.机器学习等等 ... 
- 返回void-(响应ajax,响应json格式)(了解)
			将jquery库文件加入到idea中 引入json依赖 index.jsp中 设置按钮发起ajax请求 从处理器方法返回void,响应ajax请求 MyController中 
- StringBuffer类(增删改查及长度可变原理)
			1 package cn.itcast.p2.stringbuffer.demo; 2 3 public class StringBufferDemo { 4 5 public static void ... 
- linux正则sed实战案例详解
			目录 1. 将nginx.conf中的注释全部去掉 2. 将nginx.com中每一行之前增加注释 3.要求一键修改本机的ip 4.将/etc/passwd中的root修改成ROOT 1. 将ngin ... 
