「题解」「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」切糕的更多相关文章

  1. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  2. 「HNOI2013」游走

    「HNOI2013」游走 题目描述 一个无向连通图,顶点从 \(1\) 编号到 \(N\) ,边从 \(1\) 编号到 \(M\) .小 \(Z\) 在该图上进行随机游走,初始时小 \(Z\) 在 \ ...

  3. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  4. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  5. 【题解】「P6832」[Cnoi2020]子弦

    [题解]「P6832」[Cnoi2020]子弦第一次写月赛题解( 首先第一眼看到这题,怎么感觉要用 \(\texttt{SAM}\) 什么高科技的?结果一仔细读题,简单模拟即可. 我们不难想出,出现最 ...

  6. 「题解报告」 P3167 [CQOI2014]通配符匹配

    「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...

  7. 「bzoj1003」「ZJOI2006」物流运输 最短路+区间dp

    「bzoj1003」「ZJOI2006」物流运输---------------------------------------------------------------------------- ...

  8. 「bzoj1925」「Sdoi2010」地精部落 (计数型dp)

    「bzoj1925」「Sdoi2010」地精部落---------------------------------------------------------------------------- ...

  9. 「BZOJ1924」「SDOI2010」 所驼门王的宝藏 tarjan + dp(DAG 最长路)

    「BZOJ1924」[SDOI2010] 所驼门王的宝藏 tarjan + dp(DAG 最长路) -------------------------------------------------- ...

随机推荐

  1. Linux常用命令英文全称与中文解释 (pwd、su、df、du等)

    https://blog.csdn.net/qq_40334837/article/details/83819735 Linux常用命令英文全称与中文解释 apt: Advanced Packagin ...

  2. Github Pull Request的提出与采纳

    这一文来简要介绍一下Github Pull Request(以下简称PR)的使用方法: 作为PR的提出者,如何对某个仓库提交PR,如何根据仓库管理者对所提交PR的反馈对PR进行完善 作为PR的接收者, ...

  3. opencv:图像模糊

    高斯模糊 #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespa ...

  4. Java进阶学习(3)之对象容器.小练习

    查找里程(10分) 题目内容: 下图为国内主要城市之间的公路里程: 你的程序要读入这样的一张表,然后,根据输入的两个城市的名称,给出这两个城市之间的里程. 注意:任何两个城市之间的里程都已经给出,不需 ...

  5. ajax请求ashx跨域问题解决办法

    ajax请求ashx跨域问题解决办法 https://blog.csdn.net/windowsliusheng/article/details/51583566 翻译windowsliusheng  ...

  6. 洛谷 P1464 Function(简单记忆化)

    嗯... 让一切从水开始吧... 水过初赛,但愿复赛能够接着水过... 这道题不记忆化会tle,所以用空间换时间,将每次的答案(只有20*20*20个)存下来,如果之前已经求过,就不需要重复求了... ...

  7. php mongdb driver 1.17

    Installation To build and install the driver: $ pecl install mongodb $ echo "extension=mongodb. ...

  8. socket实现简单的FTP

    一.开发环境 server端:centos 7  python-3.6.2 客户端:Windows 7 python-3.6.2 pycharm-2018 程序目的:1.学习使用socketserve ...

  9. .NET中的字符串(2):你真的了解.NET中的String吗?

    概述 String在任何语言中,都有它的特殊性,在.NET中也是如此.它属于基本数据类型,也是基本数据类型中唯一的引用类型.字符串可以声明为常量,但是它却放在了堆中.希望通过本文能够使大家对.NET中 ...

  10. 给Linux安装中文的man手册

    查找 yum list |grep man.*zh 安装 sudo yum install man-pages-zh-CN.noarch 配置 alias cman='man -M /usr//sha ...