网络流 方格取数类型题的总结 + 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

相关文章

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如