当前位置: 首页 > news >正文

圈地游戏(分数规划、网格图对偶建模)

原题链接:圈地游戏

题目大意

叮咚鸡家里有一块地,由 n n n m m m 行的方格组成,各自内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用。叮咚鸡喜欢在地里散步,它可以从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或接触(出发点除外)。记这条封闭路线内部的格子总价值为 V V V,路线上的费用总和为 C C C,叮咚鸡想知道 V C \frac{V}{C} CV 的最大值是多少。
样例输入
第一行为两个正整数 n , m n,m n,m
接下来 n n n 行,每行 m m m 个非负整数,表示对应格子的价值。
接下来 n + 1 n+1 n+1 行,每行 m m m 个正整数,表示所有横向的格线上的费用。
接下来 n n n 行,每行 m + 1 m+1 m+1 个正整数,表示所有纵向的格线上的费用。

3 4
1 3 3 3
1 3 1 1
3 3 1 0
100 1 1 1
97 96 1 1
1 93 92 92
1 1 90 90
98 1 99 99 1
95 1 1 1 94
1 91 1 1 89

样例输出

1.286

题目分析

  • 这是典型的分数规划结合网络流的题目,对于最终收益的最大值 V C \frac{V}{C} CV,假设当前二分的值为 λ \lambda λ,那么有 V C > λ \frac{V}{C}\gt\lambda CV>λ,也就是说当 V − λ × C > 0 V-\lambda\times C\gt0 Vλ×C>0 时当前 λ \lambda λ 未达到最大值,需要调整下界 l l l λ \lambda λ;反之则需要调整上界 r r r λ \lambda λ
  • 考虑如何计算 V − λ × C V-\lambda\times C Vλ×C 的最大值,对于网格图,很自然想到用网格图的对偶图建模,由于网格中无自然流的流向确定,因此将每一个网格视为选或者不选的问题,,而选或不选的问题又常常可以被转化为最小割问题。
  • 采取最大权闭合图思想寻找最大化 V − λ × C V-\lambda\times C Vλ×C 的选择方案: max ⁡ ( P s e l − C o s t ) = ∑ P a l l − min ⁡ Cut \max(P_{sel}-Cost)=\sum P_{all}-\min\text{Cut} max(PselCost)=PallminCut取源点 S S S,汇点 T T T,从每个 S S S 向每个格点连边,容量为该格点权值;从每个格点向四周连边,容量为对应接触的边的权值,如果为外部面,则向 T T T 连边,即 T T T 视作外部面标号。考虑下简化图结构:例图1
    对于价值边,如果不选择 u u u,那么最小割需要加入 P u P_u Pu;对于代价边,其发生在相邻两节点一个被选一个不被选的情况,如若此时不选择 u u u 但选择了 v v v,为了彻底割去 u u u,最小割在加入 P u P_u Pu 的基础上还要加上 λ × ( c ( u , v ) + c ( v , T ) \lambda\times(c(u,v)+c(v,T) λ×(c(u,v)+c(v,T)
  • 在建图时可用如下形式对索引为 i d x idx idx 的横边或者竖边映射到对偶图中的对应两个节点。用 u p up up d o w n down down 表示标号为 i d x idx idx 的横边上下的节点标号;用 l e f t left left r i g h t right right 表示标号为 i d x idx idx 的竖边左右的节点标号。
int up(int idx) {return (idx <= m ? T : idx - m);}
int down(int idx) {return (idx > n * m ? T : idx);}
int left(int idx) {return ((idx % (m + 1)) == 1 ? T : idx - (idx - 1) / (m + 1) - 1);}
int right(int idx) {return ((idx % (m + 1)) == 0 ? T : idx - idx / (m + 1));}

代码答案

#include<bits/stdc++.h>
#define endl '\n'
#define ll long longusing namespace std;const int N = 3e3 + 10, M = 5e5 + 10;
const double DINF = 1e18;
int n, m, tot = 1, rd[M], cd[M], bx[N][N], S, T;
int d[N], cur[N], head[N];int sgn(double x) {if(fabs(x) < 1e-6) return 0;return x > 0 ? 1 : -1;
}struct edge {int v, nxt; double c;
} edges[M];int up(int idx) {return (idx <= m ? T : idx - m);}
int down(int idx) {return (idx > n * m ? T : idx);}
int left(int idx) {return ((idx % (m + 1)) == 1 ? T : idx - (idx - 1) / (m + 1) - 1);}
int right(int idx) {return ((idx % (m + 1)) == 0 ? T : idx - idx / (m + 1));}void add(int u, int v, double c, int k = 1) {edges[++tot] = {v, head[u], c};head[u] = tot;edges[++tot] = {u, head[v], k * c};head[v] = tot;
}bool bfs() {fill(d, d + N, 0);queue<int> q;d[S] = 1; q.push(S);while(q.size()) {int u = q.front(); q.pop();for(int i = head[u]; i; i = edges[i].nxt) {int v = edges[i].v;if(!d[v] && sgn(edges[i].c) > 0) {d[v] = d[u] + 1;q.push(v);if(v == T) return true;}}}return false;
}double dfs(int u, double mf) {if(u == T) return mf;double s = 0;for(int i = cur[u]; i; i = edges[i].nxt) {cur[u] = i;int v = edges[i].v;if(d[v] == d[u] + 1 && sgn(edges[i].c) > 0) {double res = dfs(v, min(mf - s, edges[i].c));edges[i].c -= res;edges[i ^ 1].c += res;s += res;if(sgn(s - mf) == 0) break;}}if(sgn(s) == 0) d[u] = 0;return s;
}double dinic() {double flow = 0;while(bfs()) {memcpy(cur, head, sizeof head);flow += dfs(S, DINF);}return flow;
}int main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;S = 0, T = n * m + 1;for(int i = 1; i <= n; i++) {for(int j = 1; j <= m; j++)	cin >> bx[i][j];}for(int i = 1; i <= n + 1; i++) {for(int j = 1; j <= m; j++) cin >> rd[(i - 1) * m + j];}for(int i = 1; i <= n; i++) {for(int j = 1; j <= m + 1; j++) cin >> cd[(i - 1) * (m + 1) + j];}auto check = [&](double lam) -> bool {tot = 1;fill(head, head + N, 0);double s = 0;for(int i = 1; i <= n; i++) {for(int j = 1; j <= m; j++) {add(S, (i - 1) * m + j, bx[i][j], 0);s += bx[i][j];}}for(int i = 1; i <= n + 1; i++) {for(int j = 1; j <= m; j++) {int idx = (i - 1) * m + j;add(up(idx), down(idx), lam * rd[idx]);}}for(int i = 1; i <= n; i++) {for(int j = 1; j <= m + 1; j++) {int idx = (i - 1) * (m + 1) + j;add(left(idx), right(idx), lam * cd[idx]);}}return sgn(s - dinic()) > 0;};double l = 0, r = DINF;while(sgn(r - l) > 0) {double mid = (r + l) / 2;(check(mid) ? l : r) = mid;}cout << fixed << setprecision(3) << l << endl;return 0;
}
http://www.dtcms.com/a/525558.html

相关文章:

  • 工商注册官方网站北京软件开发公司官网
  • 南充网站建设服务商互动平台
  • 电影网站html模板屋领网站固链
  • marm_ros2 机械臂视觉抓取操作流程
  • 像淘客基地这样的网站如何做网站引导页在线做
  • Wordpress 仿站 工具深圳金科威公司官网
  • python在Arcgis Pro中 多边形锐角识别与切割脚本笔记
  • 一种使用 PowerToys 的键盘管理器工具编辑惠普暗影精灵11 的 OMEN 自定义按键的方法
  • 锂电池充放电管理学习
  • 复数等式:为何对所有整数都成立?
  • CLIP模型全解析:从对比学习到零样本识别的革命
  • 广州网站优化步骤用公司网站后缀做邮箱
  • 202.快乐数
  • 黑色asp企业网站源码办公空间设计说明300字
  • 站群 网站如何做网站页面设计网页说明
  • 昆山的网站建设网站建设改手机号
  • HTML:Video视频切换时不重新加载
  • CSP-S模拟赛六总结
  • 网站开发工具中的三剑客湖南建设人力资源网证书查询
  • 朝阳网站推广网站开发费用说明
  • seo做的好的网站有哪些东莞最新招聘
  • seo网站优化多少钱全球咨询公司排名
  • ElementPlus 如何支持移动端
  • 家庭服务器分享
  • xv6 第二章_操作系统架构
  • 创建网站要多长时间网站链接只显示到文件夹怎么做的
  • 写出网站开发的基本流程wordpress nova 汉化
  • 1024~
  • 选图片的网站网站引流.
  • Java的内部类介绍