「题解」「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. Drf模块详细分析

    drf的请求模块 drf的request是在wdgi的request基础上再次封装 wsgi的request作为drf的request一个属性:_request 新的request对旧的request ...

  2. 【Angular】关于angular引用第三方组件库无法改变其组件样式 :host ::ng-deep

    [Angular]关于angular引用第三方组件库无法改变其组件样式 :host ::ng-deep css修改:无效 .ant-input-affix-wrapper .ant-input:not ...

  3. ftrace使用

    前段时间遇到个问题,有个后继音频数据处理线程调度不及时导致音频输出延迟,音视频不同步. 因此从系统上入手,采用ftrace进行debug,来看有哪些线程会去抢占音频数据处理线程. ftrace 提供了 ...

  4. C#中的循环:while do...while for

    循环:重复将相同或类似规律的代码进行反复执行 减少代码冗余  可维护  可扩展 while(bool) { ...; } 代码块中可以使用break或者continue中断 break:中断整个循环 ...

  5. c# 异常:值不能为 null。 参数名: source

    异常详细信息: System.ArgumentNullException: 值不能为 null.参数名: source 其实问题那就出在 Select() 方法,在 Select 上按 F12 查看定 ...

  6. 清华大学慕课 (mooc) 数据结构-邓俊辉-讲义-合并版

    邓公的数据结构一直好评如潮,可惜我如今才开始学习它.QAQ 昨天,<数据结构 (2020 春)>的讲义已经推到清华大学云盘上了.苦于 10 拼页的打印版不易在 PC 上阅读(手机上更是如此 ...

  7. python web django 2nd level -- 待更新

    练习代码位置 实例代码位置 --> app: myblog Form 利用Form表单验证,自己写的html 思路: 新建一个类 LoginForm(forms.Form) 新建对象 obj = ...

  8. 华硕笔记本(i76700hq+nvidia goforce940mx)安装ubuntu18.04

    Ubuntu的安装 今天终于下定决心要把笔记本安装成Ubuntu,但是网上的教材不够全面,我就想整合以下教程. 接下来详细讲解安装过程 1. Ubuntu iso镜像下载 下载地址:https://w ...

  9. oracle 基础sql语句

    修改date日期时间: update T2_FOODS_STORAGE_IN set create_time =to_date('2020-01-15 12:30:20','yyyy-mm-dd hh ...

  10. 再次配置caffe-windows vs2015+cuda10.0+RTX2070+python3.5

    前段时间换了一个配置高一点的台式机,因此重新安装了caffe,这次安装遇到了很多以前没有遇到的问题,特记录一下. 先罗列一下电脑配置:vs2015+cuda10.0+python3.5(Anacond ...