• [HNOI2013] 切糕


    此处有图:传送门!!不过图好像左右画反了。。emmm

    理解一下这样建图的效用:设在一个纵(竖)轴上割开的点高度是h(建图是已经当边处理了,所以多搞了一层点。。),那么最小割一定不会在这根纵轴的相邻轴出再割掉一个高度小于h-d的边。这就保证了题目中"对于所有的 1≤x,x’≤P 和 1≤y,y’≤Q,若|x-x’|+|y-y’|=1,则|f(x,y)-f(x’,y’)| ≤D,其中 D 是给定的一个非负整数"的要求。

    真是一个经典的最小割模型呢

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=7e5+10;
    const int L=2e6+10;
    const int inf=0x3f3f3f3f;
    
    int S=N-1,T=N-2;
    int head[N],to[L],upp[L],last[L],cnt=1;
    int que[N],lev[N],hd,tl;
    
    inline void add_edge(int x,int y,int u1,int u2=0) {
    	to[++cnt]=y,upp[cnt]=u1,last[cnt]=head[x],head[x]=cnt;
    	to[++cnt]=x,upp[cnt]=u2,last[cnt]=head[y],head[y]=cnt; 
    }
    inline bool bfs() {
    	memset(lev,0,sizeof lev);
    	lev[S]=1;
    	que[hd=0,tl=1]=S;
    	while(hd<tl) {
    		int x=que[++hd];
    		for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && !lev[to[i]]) 
    			lev[to[i]]=lev[x]+1, que[++tl]=to[i];
    	}
    	return lev[T]!=0;
    }
    int dfs(int x,int tf) {
    	if(x==T) return tf;
    	int tot=0,tmp;
    	for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && lev[x]+1==lev[to[i]]) {
    		tmp=dfs(to[i],min(tf-tot,upp[i]));
    		if(tmp) upp[i]-=tmp,upp[i^1]+=tmp,tot+=tmp;
    		if(tot==tf) break;
    	}
    	if(!tot) lev[x]=-1;
    	return tot;
    }
    
    int p,q,r,d;
    int id[50][50][50];
    
    const int fx[]={-1,1,0,0};
    const int fy[]={0,0,-1,1};
    
    int main() {
    	scanf("%d%d%d%d",&p,&q,&r,&d);
    	int cnt=0, x;
    	for(int i=1; i<=r+1; ++i) {
    		for(int j=1; j<=p; ++j) {
    			for(int k=1; k<=q; ++k) {
    				id[i][j][k]=++cnt;
    			}
    		}
    	}
    	for(int i=1; i<=r; ++i) {
    		for(int j=1; j<=p; ++j) {
    			for(int k=1; k<=q; ++k) {
    				scanf("%d",&x);
    				add_edge(id[i][j][k],id[i+1][j][k],x);
    			}
    		}
    	}
    	for(int i=1; i<=p; ++i) {
    		for(int j=1; j<=q; ++j) {
    			add_edge(S,id[1][i][j],inf);
    			add_edge(id[r+1][i][j],T,inf);
    		}
    	}
    	for(int i=d+1; i<=r+1; ++i) {
    		for(int j=1; j<=p; ++j) {
    			for(int k=1; k<=q; ++k) {
    				for(int x,y,t=0; t<4; ++t) {
    					if(id[x=j+fx[t]][y=k+fy[t]]) {
    						add_edge(id[i][j][k],id[i-d][x][y],inf);
    					}
    				}
    			}
    		}
    	}
    	int ans=0;
    	while(bfs()) ans+=dfs(S,inf);
    	printf("%d
    ",ans);
    	return 0;
    } 
    
  • 相关阅读:
    photoshop--图像大小(分辨率和宽高)
    Arduino--单向倾斜开关
    禁止google浏览器http链接强制跳转为https
    属性缓存_使用ConcurrentDictionary替代Hashtable对多线程的对象缓存处理
    .Net(windows服务器)清理缓存数据的几个方法
    【西天取经】(升级.net5)用了一整天才把项目从.netcoreapp3.1升级到.net5(转载)
    在Debian 9 vim中启用鼠标复制粘贴
    将数据批量插入SQL Server
    shell 脚本中 在grep -E '($wo|$ni|$ta)' 这里面用变量
    kubernetes 重启的几种方法
  • 原文地址:https://www.cnblogs.com/nosta/p/10174728.html
Copyright © 2020-2023  润新知