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

The 2025 ICPC Asia East Continent Online Contest (I) - H.Walk(网格图对偶建模、最小割建模)

原题链接:Walk

题目大意

在二维平面上,你初始位于点 (0,0)(0, 0)(0,0),目标是前往点 (N,M)(N, M)(N,M)。若你当前处于位置 (x,y)(x, y)(x,y),下一步可移动到 (x+1,y)(x + 1, y)(x+1,y)(x,y+1)(x, y + 1)(x,y+1)。你走过的路径定义为:依次连接每一步位置所形成的、从 (0,0)(0, 0)(0,0)(N,M)(N, M)(N,M) 的折线。

存在 KKK 个矩形。第 iii 个矩形的左下角坐标为 (xi,1−0.5,yi,1−0.5)(x_{i,1} − 0.5, y_{i,1} − 0.5)(xi,10.5,yi,10.5),右上角坐标为 (xi,2+0.5,yi,2+0.5)(x_{i,2} + 0.5, y_{i,2} + 0.5)(xi,2+0.5,yi,2+0.5)。若你走的路径同时与该矩形的左边界和右边界相交,需承担 aia_iai 的成本;若路径同时与该矩形的上边界和下边界相交,需承担 bib_ibi 的成本。总费用定义为所有矩形产生的成本之和。

你需要求出从 (0,0)(0, 0)(0,0)(N,M)(N, M)(N,M) 所需的 最小总费用

样例输入

1 2 1
0 1 1 1 1 2

样例输出

2

题目分析

  • 经典的网格图转对偶图处理,对于每一个方格/横边/竖边,从左到右,从上到下标号,对于一张 n×mn\times mn×m 的网格图,网格图中的标号 idxidxidx 的边与对偶图中 (u,v)(u,v)(u,v) 有如下关系,其中 updown 用于找横边,leftright 用于找竖边:
// S 为源点, T 为汇点
int up(int idx) {return idx <= m ? S : 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 ? S : idx - idx / (m + 1);}

例图1

  • 此时网格图上的一条合法路径对应对偶图上的一个割,现分析同时穿过矩形左右/上下两边在对偶图上的表现形式。图中绿色有向线为网络流流向,红色线框为矩形,橙色有向线为一条从 (0,0)(0,0)(0,0)(N,M)(N,M)(N,M) 的合法路径。任意一条合法路径(即一个割)都如图所示,将左上半部分划分到 S′S'S 中,将下半划分到 T′T'T 中。考虑最下方的矩形,也就是路线穿过矩形上下两边的情况,容易发现该路线将节点 4,74,74,7 划分到了 S′S'S 中,将节点 6,96,96,9 划分到了 T′T'T 集合当中,若改变路径但使得其同样穿过矩形上下两边,那么恒有节点 4,74, 74,7 被划分到 S′S'S 中,节点 6,96,96,9 被划分到 T′T'T 中。
  • 分析发现,若节点 777 被划分到了 S′S'S 且节点 666 被划分到了 T′T'T,那么必有 777 号节点及其左上半所有部分都被划分到了 S′S'S666 号节点及其右下部分都被划分到了 T′T'T 中,由于 444 号节点为矩形左上角对应节点,故其相对于矩阵左下角节点而言,必在其左上方,对于 999 号节点同理分析,所以 777 号节点被划分到 S′S'S666 号节点被划分到 T′T'T 为路线穿过矩形上下两边的充要条件。故有,当矩形左下角对应节点被划分到 S′S'S 且矩形右上角对应节点被划分到 T′T'T 时路线穿过矩形上下两边;同理分析有,当矩形左下角对应节点被划分到 T′T'T 且矩形右上角对应节点被划分到 S′S'S 时路线穿过矩形左右两边
  • 故问题变为关于两点关系最小化组合代价问题,当且仅当两点被划分到不同集合时才会有对应代价,取左下角对应节点为 xxx,右上角对应节点为 yyy,根据该问题一般建模模型可知,连边 x→yx\to yxy,容量为 bbb;连边 y→xy\to xyx,容量为 aaa。当 x,yx,yx,y 被划分到同一集合时,这两条边边不会产生任何作用,当且仅当 x,yx,yx,y 被划分到不同集合中时,最小割才会加进去对应的组合代价,
  • 由于网格图中的一个合法路径一定是最短路,而对偶图中的最小割对应一条网格图当中的最短路,但原问题中的路径没有权值,为了确保路径是最短路,给对偶图中每一个边容量设置为一个足够大的整数 WWW,保证了其一定沿最短路行动,最小割即为 (n+m)⋅W(n+m)\cdot W(n+m)W。在加入组合代价对应的连边之后,求得最小割后再将其数值减去 (n+m)⋅W(n+m)\cdot W(n+m)W 即可。

代码答案

#include<bits/stdc++.h>
#define endl '\n'using namespace std;
using ll = long long;const ll INF = 5e7;
const ll LLINF = 0x3f3f3f3f3f3f3f3fll;const int N = 1e4 + 10, M = 2e6 + 10;
int n, m, k, S, T, tot = 1;
int head[N], cur[N], d[N];struct edge {ll v, nxt, c;
} edges[M];void add(int u, int v, ll c) {edges[++tot] = {v, head[u], c}, head[u] = tot;edges[++tot] = {u, head[v], 0}, head[v] = tot;
}bool bfs() {memset(d, 0, sizeof(d));queue<int> q;q.push(S); d[S] = 1;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] && edges[i].c) {d[v] = d[u] + 1;q.push(v);if(v == T) return true;}}}return false;
}ll dfs(int u, ll mf) {if(u == T) return mf;ll sum = 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 && edges[i].c) {ll res = dfs(v, min(edges[i].c, mf - sum));edges[i].c -= res;edges[i ^ 1].c += res;sum += res;if(sum == mf) break;}}if(!sum) d[u] = 0;return sum;
}ll dinic() {ll flow = 0;while(bfs()) {memcpy(cur, head, sizeof(head));flow += dfs(S, INF);}return flow;
}int up(int idx) {return idx <= m ? S : idx - m;}
int down(int idx) {return idx > n * m ? T : idx;}
int left(int idx) {return (idx % (m + 1)) == 1 ? S : idx - (idx - 1) / (m + 1) - 1;}
int right(int idx) {return (idx % (m + 1)) == 0 ? T : idx - idx / (m + 1);}int main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m >> k;swap(n, m);S = 0, T = n * m + 1;for(int i = 1; i <= n + 1; i++) {for(int j = 1; j <= m; j++) {int id = (i - 1) * m + j;add(up(id), down(id), INF);}}for(int i = 1; i <= n; i++) {for(int j = 1; j <= m + 1; j++) {int id = (i - 1) * (m + 1) + j;add(left(id), right(id), INF);}}for(int i = 1; i <= k; i++) {int x1, y1, x2, y2, a, b; cin >> x1 >> y1 >> x2 >> y2 >> a >> b;if((x1 == 0 && y1 == 0) || (x2 == m && y2 == n)) continue;int ld = (n - y1) * m + x1, ru = (n - y2 - 1) * m + x2 + 1;if(x1 == 0) ld = S;else if(y1 == 0) ld = T;if(x2 == m) ru = T;else if(y2 == n) ru = S;add(ld, ru, b), add(ru, ld, a);}cout << dinic() - INF * (n + m) << endl;return 0;
}
http://www.dtcms.com/a/550179.html

相关文章:

  • 网站的后缀名怎么建设おっさんとわたし天堂
  • 平台网站建设后台源码怎么做p2p网站
  • 网站设计风格方案昌乐网站设计
  • Java 与 C 差异
  • OAuth 2.0 安全授权
  • Rust 与数据库连接池的集成:安全与性能的深度耦合
  • 台州网站策划台州网站策划首页制作教程
  • 中国站长站甘肃省住房和建设厅官方网站
  • Golang学习笔记:后端性能优化秘籍(持续更新)
  • Easyx图形库应用(基础的AI开发原理)
  • arthas实现类的热部署
  • Rust 注释与文档注释:从代码可读性到 API 文档化的工程实践
  • 取名网站怎么做2022年新闻摘抄十条简短
  • 网站开发工具教程wordpress 关键词获取
  • tensorflow的广播机制
  • MIT-最大连续子序列和(MCS)
  • 深圳市住建局网站官网济南网站建设公司哪家好
  • Kubernetes资源管理全解析
  • 郑州企业型网站建设怎么做可以访问网站
  • 网站制作前必须做的事情有哪些网站行业
  • TC3xx芯片ACCEN寄存器保护详解
  • Linux上如何挂载磁盘
  • 卫星轨道计算中的数值精度陷阱:第三体引力摄动的稳定性优化
  • 白山网站seoe网站的图标怎么做
  • RHSCA---用户和组管理
  • 温州网站域名注册服务公司易语言如何做浏网站
  • 仿糗事百科网站源码dede二次开发分享+评论+互动国外网站域名
  • 仓颉语言中String的内存表示深度解析
  • NetSuite 中自定义基础打印模板的调整方法分享
  • 东城企业网站开发什么网站能免费做简历