网络流 方格取数类型题的总结 + HDU3820

2024-05-10 12:08

本文主要是介绍网络流 方格取数类型题的总结 + HDU3820,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目分析:最小割!

方格取数一类问题!

现在就这一类做一个小结吧。。。。

1.首先是方格内有固定的权值,可以取不相邻的数,问怎样取使权值最大。

这样我们奇偶建图,源点掌管奇属性点,汇点掌管偶属性点,然后相邻的两点建边容量无穷大,源汇向自己掌管的点建边,容量为权值。这样建图的意义在于,如果某一条边被割掉,那么久说明这个点被抛弃了(不选这个点),那么可不可能选到两个相邻的点?由于相邻两点的边为无穷大,那么这条边肯定不会被割掉,也就是说要么和源点相连的点被割掉,要么和汇点相连的被割掉!这样建图,被割掉一定是和源点或汇点相连的边,切记。结果是权值总和减去最小割。

两点间建边无穷大,可以这么认为,目的是为了最大化取的点是相邻点的代价,通过这种方式使得相邻两点必定不能同时取(否则这个代价太大)。


2.方格内有固定权值,可以取相邻的数,如果相邻的数被取走,那么需要付出一个这两个数同时被取走的代价,问怎样取使得权值最大。

同样奇偶建图,源汇分别和自己掌管的点建边,容量为权值。现在重点来了,因为可以同时取走相邻的点,那么我们相邻点之间就不能建边无穷大来约束了。其实约束条件其实就是相邻两点被取走的代价。怎么理解?如果同时取走两点的代价超过取走这两点带来的价值,那么说明这个方案不是最优的,因为显然我们可以只取其中一点。第一类问题其实就是通过将约束条件无穷大化来约束使得不能同时选择相邻的两点而已。


3.方格内有两种属性的权值,每个方格可以取其中一个属性的权值,可以取相邻的数,如果取走的相邻方格属于同一属性,需要花费相应的代价,问怎样取使得权值最大。

建图稍微不同:奇属性的格子的第一种属性和源点建边,第二种属性和汇点建边,容量为该属性在该格子对应的权值。偶属性的格子的第一种属性和汇点建边,第二种属性和源点建边,容量为该属性在该格子对应的权值。这样由于同一个格子我们只能取走其中一个属性的权值,那么对这两个属性建边无穷大约束一下就好。相邻两点取走相同属性怎么办?其实只要对该点的和源点相连的属性对相邻点的同一属性建边就行了(相邻点和该点同一属性则相邻点的该属性必定和汇点相连),约束条件就是代价。这样建图以后,每个点要么选取其中一个属性,要么都不选。


总结一下这一类问题,基本是奇偶建图,然后如果要求能取相邻点,那么相邻点建边,容量为代价,否则建边无穷大约束。建边无穷大可以约束两个条件使至多只能选取一个。


本题属于第三种情况。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int int_max = 0x07777777;
const int int_min = 0x80000000;
const int maxn = 55*55*2;struct Edge{int from, to, cap, flow;Edge(int _from, int _to, int _cap, int _flow):from(_from),to(_to),cap(_cap),flow(_flow){}
};
vector<Edge> es;
vector<int> g[maxn];
int result,n,m,s,t,G,S;
int p[maxn],d[maxn],gap[maxn],cur[maxn],A[55][55],B[55][55];
void addedge (int from, int to, int cap){es.push_back(Edge(from, to, cap, 0));es.push_back(Edge(to, from, 0,0));int num = es.size();g[from].push_back(num-2);g[to].push_back(num-1);
}
void BFS (){queue<int> q;memset(d, 0, sizeof(d));d[t] = 0;q.push(t);while(!q.empty()){int u = q.front();q.pop();for(int i = 0; i < g[u].size(); i++){Edge& e = es[g[u][i]];if(e.cap==0 && d[e.to]==0){d[e.to] = d[u]+1;q.push(e.to);}}}
}
int augment (){int x = t;int a = int_max;while(x!=s){Edge& e = es[p[x]];a = (a < e.cap-e.flow ? a : e.cap-e.flow);x = es[p[x]].from;}x = t;while(x!=s){es[p[x]].flow += a;es[p[x]^1].flow -= a;x = es[p[x]].from;}return a;
}
int sap (){int flow = 0;BFS();memset(gap, 0, sizeof(gap));for(int i = 0; i <= t; i++) gap[d[i]]++;int x = s;memset(cur, 0, sizeof(cur));while(d[s] < t+1){if(x==t){flow += augment();x = s;}int ok = 0;for(int i = 0; i < g[x].size(); i++){Edge& e = es[g[x][i]];if(e.cap > e.flow && d[x]==d[e.to]+1){ok = 1;p[e.to] = g[x][i];cur[x] = i;x = e.to;break;}}if(!ok){int mm = t;for(int i = 0; i < g[x].size(); i++){Edge& e = es[g[x][i]];if(e.cap > e.flow) mm = (mm > d[e.to] ? d[e.to] : mm);}if(--gap[d[x]] == 0) break;gap[d[x]=mm+1]++;cur[x] = 0;if(x!=s) x = es[p[x]].from;}}return flow;
}int main(int argc, const char * argv[])
{int T;cin >> T;int count = 0;while(T--){scanf("%d %d %d %d", &n, &m, &G, &S);int total = 0;for(int i = 0; i < n; i++){for(int j = 0; j < m; j++) {scanf("%d", &A[i][j]);total += A[i][j];}}for(int i = 0; i < n; i++){for(int j = 0; j < m; j++) {scanf("%d", &B[i][j]);total += B[i][j];}}es.clear();s = n*m*2;t = s+1;int dir[4][2] = {-1,0,0,1,1,0,0,-1};for(int i = 0; i < maxn; i++) g[i].clear();for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){if((i+j)%2==0){addedge(s, i*m+j, A[i][j]);addedge(i*m+j, i*m+j+n*m, int_max);addedge(i*m+j+n*m, t, B[i][j]);for(int u = 0; u < 4; u++){int ii = i + dir[u][0];int jj = j + dir[u][1];if(ii>=0 && ii<n && jj>=0 && jj<m){addedge(i*m+j, ii*m+jj, G);}}}else{addedge(s, i*m+j+n*m, B[i][j]);addedge(i*m+j+n*m, i*m+j, int_max);addedge(i*m+j, t, A[i][j]);for(int u = 0; u < 4; u++){int ii = i + dir[u][0];int jj = j + dir[u][1];if(ii>=0 && ii<n && jj>=0 && jj<m){addedge(i*m+j+n*m, ii*m+jj+n*m, S);}}}}}printf("Case %d: %d\n",++count,total-sap());}
}


这篇关于网络流 方格取数类型题的总结 + HDU3820的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/976395

相关文章

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Pydantic中Optional 和Union类型的使用

《Pydantic中Optional和Union类型的使用》本文主要介绍了Pydantic中Optional和Union类型的使用,这两者在处理可选字段和多类型字段时尤为重要,文中通过示例代码介绍的... 目录简介Optional 类型Union 类型Optional 和 Union 的组合总结简介Pyd

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

SpringBoot使用OkHttp完成高效网络请求详解

《SpringBoot使用OkHttp完成高效网络请求详解》OkHttp是一个高效的HTTP客户端,支持同步和异步请求,且具备自动处理cookie、缓存和连接池等高级功能,下面我们来看看SpringB... 目录一、OkHttp 简介二、在 Spring Boot 中集成 OkHttp三、封装 OkHttp

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用