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

相关文章

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Python中异常类型ValueError使用方法与场景

《Python中异常类型ValueError使用方法与场景》:本文主要介绍Python中的ValueError异常类型,它在处理不合适的值时抛出,并提供如何有效使用ValueError的建议,文中... 目录前言什么是 ValueError?什么时候会用到 ValueError?场景 1: 转换数据类型场景

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

C# dynamic类型使用详解

《C#dynamic类型使用详解》C#中的dynamic类型允许在运行时确定对象的类型和成员,跳过编译时类型检查,适用于处理未知类型的对象或与动态语言互操作,dynamic支持动态成员解析、添加和删... 目录简介dynamic 的定义dynamic 的使用动态类型赋值访问成员动态方法调用dynamic 的

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor