「题解」「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. C4K Power supply failed?

    故障log: %C4K_IOSMODPORTMAN-4-POWERSUPPLYBAD: Power supply 2 has failed or been turned off 在单机的情况下,我们可 ...

  2. Linux 下使用 ffmpeg 大批量合并 ts 文件, mp4切割文件为m3u8

    见范例 ffmpeg -i "concat:file001.ts|file002.ts|file003.ts|file004.ts......n.ts" -acodec copy ...

  3. ElementUI+Vue在使用el-dialog时,如何做到在弹出dialog时,外部呈锁定状态,而不是点击外部导致dialog直接关闭。

    ElementUI+Vue在使用el-dialog时,如何做到在弹出dialog时,外部呈锁定状态,而不是点击外部导致dialog直接关闭. 问题描述 今天,在做Element+Vue项目时发现:Di ...

  4. P&R 5

    Floorplan: 要做好floorplan需要掌握哪些知识跟技能? 通常,遇到floorplan问题,大致的debug步骤跟方法有哪些? 如何衡量floorplan的QA? 芯片的整体架构模块划分 ...

  5. 妙用python之编码转换

    转自i春秋 文章难易度:★★ 知识点:python.编码转换 前 言 在日常渗透,漏洞挖掘,甚至是CTF比赛中,会遇到各种编码,常常伴随着这些编码之间的各种转换.记得刚入门那个时候,自己处理编码转换问 ...

  6. MongoDB - 用户名密码认证

    参考 offical doc medium Mongo roles说明 https://docs.mongodb.com/manual/reference/built-in-roles/#userAd ...

  7. android nfc功能开发

    链接:Android NFC开发详细总结   https://blog.csdn.net/zhwadezh/article/details/79111348 链接2:Android NFC功能 简单实 ...

  8. 一个Log-Tan积分

    \[\Large\int_{0}^{\pi }\theta \ln\tan\frac{\theta }{2}\mathrm{d}\theta \] \(\Large\mathbf{Solution:} ...

  9. Bug搬运工-CSCvi02106 :Cisco 2800, 3800, 1560 APs: when connected to a Cisco Switch CDP-4-DUPLEX_MISMATCH log is seen

    Cisco 2800, 3800, 1560 APs: when connected to a Cisco Switch CDP-4-DUPLEX_MISMATCH log is seen CSCvi ...

  10. 消息队列(五)--- RocketMQ-消息存储1

    问题 : 部署时如何知道自己是 broker 还是 NameServer topic 订阅信息放在哪里 broker 的作用到底是什么 纪录是如何持久化的 群发的时候,是如何储存消息的 send 方法 ...