「题解」「HNOI2013」切糕
文章目录
「题解」「HNOI2013」切糕
题目描述
思路分析及代码
题目分析
这道题的题目可以说得上是史上最难看懂的题目之一了…
首先把题目重新叙述一遍。
题目大致在说,你有一个 P×Q×RP\times Q\times RP×Q×R 的蛋糕,每个点有一个不客观度 v[i][j][k]v[i][j][k]v[i][j][k] ,现在你要把这个蛋糕切开。
切蛋糕的规则是什么呢?
首先我们解释一下:
对于每一竖列,这个竖列的坐标用 (x,y)(x,y)(x,y) 表示。
也就是说,这个竖列上的点的坐标可以表示为 (x,y,i)∣i∈[1,R](x,y,i)|i\in [1,R](x,y,i)∣i∈[1,R] 。
那么,规则很好描述:
我们要在所有的 P×QP\times QP×Q 个竖列中,每个竖列选一个点。
对于一个竖列 (x,y)(x,y)(x,y) 中,把我们选的点的高表示为 f(x,y)f(x,y)f(x,y) 。
那么很好有 1≤f(x,y)≤R1\le f(x,y)\le R1≤f(x,y)≤R 。
而我们选的点的坐标就是 (x,y,f(x,y))(x,y,f(x,y))(x,y,f(x,y)) 。
竖列相邻:对于一个坐标为 (x,y)(x,y)(x,y) 的竖列,相邻即指坐标为 (i+1,j)、(i−1,j)、(i,j+1)、(i,j−1)(i+1,j)、(i-1,j)、(i,j+1)、(i,j-1)(i+1,j)、(i−1,j)、(i,j+1)、(i,j−1) 的竖列。
但是有一个限制,对于相邻的竖列,在他们上所选择的点的高度差不超过 DDD ,即:
∣f(x,y)−f(x,y±1)∣≤D , ∣f(x,y)−f(x±1,y)∣≤D|f(x,y)-f(x,y\pm1)|\le D\space, \space |f(x,y)-f(x\pm 1,y)|\le D∣f(x,y)−f(x,y±1)∣≤D , ∣f(x,y)−f(x±1,y)∣≤D
而现在我们的目的是,对于我们所有选出的点,使得 ∑v[i][j][f(i,j)]\sum v[i][j][f(i,j)]∑v[i][j][f(i,j)] 最小。
题解及代码
这道题怎么思考?
首先,我们考虑:如果没有这个 DDD ,我们应该怎么做?
这个题就转化为:求每一竖列的最短边之和。
这样的问题,似乎几个循环就可以解决。
但是,这样的题是否有些像最小割问题?
那么,此题的方法呼之欲出:网络流最大流最小割问题。
如果解决 每一竖列的最短边之和
这样的问题用网络流,建图方法很简单:
建立第 000 层与第 R+1R+1R+1 层,然后有这样的连边关系:
S−>(i,j,1),flow=INFS->(i,j,1),flow=INFS−>(i,j,1),flow=INF
(i,j,k)−>(i,j,k+1),flow=v[i][j][k]∣k∈[1,R)(i,j,k)->(i,j,k+1),flow=v[i][j][k]|k\in [1,R)(i,j,k)−>(i,j,k+1),flow=v[i][j][k]∣k∈[1,R)
(i,j,r)−>T,flow=v[i][j][r](i,j,r)->T,flow=v[i][j][r](i,j,r)−>T,flow=v[i][j][r]
但是对于此题,我们还有 DDD 的限制。
现在考虑怎么把这样的限制考虑进我们的网络流。
假设我们有这样一个图:
其中, A={p1,p2,p3,p4}A=\{p1,p2,p3,p4\}A={p1,p2,p3,p4} 代表第 aaa 列, B={p5,p6,p7,p8}B=\{p5,p6,p7,p8\}B={p5,p6,p7,p8} 代表第 bbb 列。
断言,现在的 DDD 的值为 111 。
那么,从题目的表示来说,假设我们在 AAA 中选择了 p3p3p3 ,那么我们就只能在 BBB 中选择 p6,p7,p8p6,p7,p8p6,p7,p8 。
现在,我们做一个尝试,连接一条边 edge{p3,p6}edge\{p3,p6\}edge{p3,p6} 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7JTTWIbK-1576065216359)(https://i.postimg.cc/44c0CL9P/graph-2.png)]
那么,如果我们再跑最大流时,如果我们将 edge{p5,p6}edge\{p5,p6\}edge{p5,p6} 删掉,对 path{S,p1,p2,p3,p6,p7,p8}path\{S,p1,p2,p3,p6,p7,p8\}path{S,p1,p2,p3,p6,p7,p8} 似乎没有影响。
但是又有一个问题:如果我们选的点比 p3p3p3 高出了 DDD 呢?
其实这个问题是一样的:我们连接 edge{p8,p3}edge\{p8,p3\}edge{p8,p3} ,那么就有这个图:
那么问题就解决了。
所以,我们解决 DDD 对于我们的限制,就是再添加几条边条边:
(i,j,k)−>(i±1,j,k−d)(i,j,k)->(i\pm 1,j,k-d)(i,j,k)−>(i±1,j,k−d)
(i,j,k)−>(i,j±1,k−d)(i,j,k)->(i,j\pm 1,k-d)(i,j,k)−>(i,j±1,k−d)
对于 kkk ,满足 k>dk>dk>d
那么,这个题就算是解决了。
接下来是代码。
#include<cstdio>
#include<queue>
using namespace std;
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define pii pair<int,int>
#define Endl putchar('\n')
// #define FILEOI
// #define int long long
#ifdef FILEOI
#define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
#undef MAXBUFFERSIZE
#define cg (c=fgetc())
#else
#define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXP=40;
const int INF=(1<<30)-1;
int p,q,r,d,S,T;
int v[MAXP+5][MAXP+5][MAXP+5];
struct edge{
int to,nxt,w;
edge(){}
edge(const int T,const int N,const int W):to(T),nxt(N),w(W){}
}e[(MAXP*MAXP*MAXP*10)+5];
int tail[MAXP*MAXP*MAXP*MAXP+5],ecnt;
int cur[MAXP*MAXP*MAXP*MAXP+5];
inline void add_edge(const int u,const int v,const int w){
// printf("add_edge:>u == %d, v == %d, w == %d\n",u,v,w);
e[++ecnt]=edge(v,tail[u],w);tail[u]=ecnt;
}
inline int id(const int x,const int y,const int z){return x*40*40+y*40+z;}
inline bool inside(const int x,const int y,const int z){
return 0<x && x<=p && 0<y && y<=q && 0<z && z<=r;
}
int dis[MAXP*MAXP*MAXP*MAXP+5];
inline bool bfs(){
rep(i,0,id(p,q,r)+1)dis[i]=-1;
dis[S]=0;
queue<int>Q;Q.push(S);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=tail[u],v;i;i=e[i].nxt){
v=e[i].to;
if(dis[v]!=-1 || e[i].w<=0)continue;
dis[v]=dis[u]+1;
Q.push(v);
}
}
return dis[T]!=-1;
}
int dfs(const int u,int inflow){
if(u==T)return inflow;
int sum=0,tmp,v;
for(int& i=cur[u];i;i=e[i].nxt){
v=e[i].to;
if(dis[v]!=dis[u]+1 || e[i].w<=0)continue;
tmp=dfs(v,Min(inflow-sum,e[i].w));
e[i].w-=tmp,e[i^1].w+=tmp;
if((sum+=tmp)>=inflow)break;
}
return sum;
}
inline int dinic(){
int max_flow=0;
while(bfs()){
rep(i,0,id(p,q,r)+1)cur[i]=tail[i];
max_flow+=dfs(S,INF);
}
return max_flow;
}
signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
ecnt=1;
qread(p,q,r,d);
S=0,T=id(p,q,r)+1;
// printf("S == %d, T == %d\n",S,T);
rep(k,1,r)rep(i,1,p)rep(j,1,q)qread(v[i][j][k]);
rep(i,1,p)rep(j,1,q){
add_edge(S,id(i,j,1),INF);
add_edge(id(i,j,1),S,0);
}
rep(k,1,r-1)rep(i,1,p)rep(j,1,q){
add_edge(id(i,j,k),id(i,j,k+1),v[i][j][k]);
add_edge(id(i,j,k+1),id(i,j,k),0);
if(k<=d)continue;
// puts("the special edge:");
if(inside(i+1,j,k-d)){
add_edge(id(i,j,k),id(i+1,j,k-d),INF);
add_edge(id(i+1,j,k-d),id(i,j,k),0);
}
if(inside(i-1,j,k-d)){
add_edge(id(i,j,k),id(i-1,j,k-d),INF);
add_edge(id(i-1,j,k-d),id(i,j,k),0);
}
if(inside(i,j+1,k-d)){
add_edge(id(i,j,k),id(i,j+1,k-d),INF);
add_edge(id(i,j+1,k-d),id(i,j,k),0);
}
if(inside(i,j-1,k-d)){
add_edge(id(i,j,k),id(i,j-1,k-d),INF);
add_edge(id(i,j-1,k-d),id(i,j,k),0);
}
// puts("-------------end-------------");
}
rep(i,1,p)rep(j,1,q){
add_edge(id(i,j,r),T,v[i][j][r]);
add_edge(T,id(i,j,r),0);
if(r<=d)continue;
// puts("the special edge:");
if(inside(i+1,j,r-d)){
add_edge(id(i,j,r),id(i+1,j,r-d),INF);
add_edge(id(i+1,j,r-d),id(i,j,r),0);
}
if(inside(i-1,j,r-d)){
add_edge(id(i,j,r),id(i-1,j,r-d),INF);
add_edge(id(i-1,j,r-d),id(i,j,r),0);
}
if(inside(i,j+1,r-d)){
add_edge(id(i,j,r),id(i,j+1,r-d),INF);
add_edge(id(i,j+1,r-d),id(i,j,r),0);
}
if(inside(i,j-1,r-d)){
add_edge(id(i,j,r),id(i,j-1,r-d),INF);
add_edge(id(i,j-1,r-d),id(i,j,r),0);
}
// puts("-------------end-------------");
}
int ret=dinic();
writc(ret,'\n');
return 0;
}
一道十分好的题。
「题解」「HNOI2013」切糕的更多相关文章
- 「ZJOI2019」&「十二省联考 2019」题解索引
「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...
- 「HNOI2013」游走
「HNOI2013」游走 题目描述 一个无向连通图,顶点从 \(1\) 编号到 \(N\) ,边从 \(1\) 编号到 \(M\) .小 \(Z\) 在该图上进行随机游走,初始时小 \(Z\) 在 \ ...
- 「题解」「美团 CodeM 资格赛」跳格子
目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...
- 「题解」JOIOI 王国
「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...
- 【题解】「P6832」[Cnoi2020]子弦
[题解]「P6832」[Cnoi2020]子弦第一次写月赛题解( 首先第一眼看到这题,怎么感觉要用 \(\texttt{SAM}\) 什么高科技的?结果一仔细读题,简单模拟即可. 我们不难想出,出现最 ...
- 「题解报告」 P3167 [CQOI2014]通配符匹配
「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...
- 「bzoj1003」「ZJOI2006」物流运输 最短路+区间dp
「bzoj1003」「ZJOI2006」物流运输---------------------------------------------------------------------------- ...
- 「bzoj1925」「Sdoi2010」地精部落 (计数型dp)
「bzoj1925」「Sdoi2010」地精部落---------------------------------------------------------------------------- ...
- 「BZOJ1924」「SDOI2010」 所驼门王的宝藏 tarjan + dp(DAG 最长路)
「BZOJ1924」[SDOI2010] 所驼门王的宝藏 tarjan + dp(DAG 最长路) -------------------------------------------------- ...
随机推荐
- 优酷1080p的kux格式文件怎么转换为MP4格式?
直接使用优酷自己的FFMPEG解码! 格式为:"优酷ffmpeg.exe的安装地址" -y -i ".kux文件储存地址" -c:v copy -c:a cop ...
- Java - Test - TestNG: testng.xml 元素 package
1. 概述 简介 package 元素 packages package exclude include 2. 背景 准备 自动生成了 testng.xml 文件 已经基本了解了 testng.xml ...
- 【经典数据结构】B树与B+树的解释
本文转载自:http://www.cnblogs.com/yangecnu/p/Introduce-B-Tree-and-B-Plus-Tree.html 前面讲解了平衡查找树中的2-3树以及其实现红 ...
- MySQL表的操作02
[1]设置非空约束(NOT NULL ,NK)--->>>目的是f防止某些字段中的内容为空 CREATE TABLE +table_name ( 属性名 数据类型 NOT N ...
- SVN代码迁移到GITlab
==================================================================================================== ...
- python进阶(十七)xml(下)
1.XML简介 xml用到的地方:tomcat配置文件 1) xml 指可扩展标记语言(Extensible Markup Language) 2) xml 被设计用于结构化.存储和传输数据 3) x ...
- 反混淆 de4dot
使用SmartAssembly\Dotfuscator等混淆后,反编译应用程序时如何破解? 一款非常NB的反混淆工具:de4dot(开源) Github地址:https://github.com/0x ...
- IE6下的png不透明问题
前几天刚做完一个小需求,但是在兼容ie方面用了比较久的时间,主要是切面那边用的背景图都是png格式的,而经过查找知道,ie6对png图片透明部分渲染效果是不透明的,我看到的是淡淡的绿色,简单的处理方式 ...
- NTP服务安装及时间同步
1.安装ntp服务命令 yum install -y ntp 2.常用NTP服务器地址: ntp1.aliyun.com ntp2.aliyun.com ntp3.aliyun.com ntp4.al ...
- 神奇的requestAnimationFrame解决传统定时器bug
可能你还没见过这个东西是个啥,其实他就是类似于setTimeout和setInterval,然而它与setTimeout和setInterval又有所不同,requestAnimationFrame不 ...