• Luogu3227 HNOI2013切糕


    My blog

    Description

    link

    给定一个 (n,m,h) 的立方体,每个点有代价,现在在每个纵轴上面找一个点,使得所有的代价的和最小

    限制:相邻的纵轴上找的点的位置距离差不能超过一个给定的值 (d)

    Solution

    最小割,割掉的边是要切掉的点

    从源点向第一层的点连 (inf)

    这里还有一个点化边,然后新建一层,接着从上面一层的每一个点向下面的点连上一条边权为点的代价的边

    最后一层((h+1) 层)往汇点连一条边权为 (inf) 的边

    然后我们考虑怎么对付这个限制

    其实这个限制在图上就变成了我们在考虑一个 ((x,y,k)) 之后必须选 ((x+dx,y+dy,k pm d))

    啊这里 (dx)(dy) 表示四向相邻点

    那么就是必经边呗,连上个 (inf) 就成了

    然后跑个最小割就好了

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=1e5+10;
    	struct node{
    		int to,lim,nxt;
    	}e[N<<1];
    	int head[N],cnt=1,dep[N],S,T;
    	queue<int> Q;
    	inline void adde(int u,int v,int w)
    	{
    		e[++cnt].lim=w; e[cnt].nxt=head[u]; e[cnt].to=v;
    		return head[u]=cnt,void();
    	}
    	inline void add(int u,int v,int w){return adde(u,v,w),adde(v,u,0);}
    	inline bool bfs()
    	{
    		memset(dep,0,sizeof(dep)); dep[S]=1; 
    		while(Q.size()) Q.pop(); Q.push(S);
    		while(Q.size())
    		{
    			int fr=Q.front(); Q.pop();
    			for(int i=head[fr];i;i=e[i].nxt)
    			{
    				int t=e[i].to; 
    				if(e[i].lim&&!dep[t]) dep[t]=dep[fr]+1,Q.push(t);
    			}
    		} return dep[T];
    	}
    	inline int dfs(int now,int in)
    	{
    		int out=0; if(now==T) return in;
    		for(int i=head[now];in&&i;i=e[i].nxt)
    		{
    			int t=e[i].to; 
    			if(e[i].lim&&dep[now]==dep[t]-1) 
    			{
    				int res=dfs(t,min(e[i].lim,in));
    				in-=res; out+=res; e[i].lim-=res; e[i^1].lim+=res;
    			}
    		} if(!out) dep[now]=0;
    		return out;	
    	}
    	int v[110][110][100],p,q,r,d;
    	inline int id(int x,int y,int z){return p*q*(z-1)+y+(x-1)*q;}
    	int fx[4]={0,1,0,-1};
    	int fy[4]={1,0,-1,0};
    	inline bool in(int x,int y){return x>=1&&x<=p&&y>=1&&y<=q;}
    	signed main()
    	{
    		p=read(),q=read(); r=read(); d=read();
    		S=p*q*(r+1)+1,T=p*q*(r+1)+2; 
    		for(int k=1;k<=r;++k)
    		{
    			 for(int i=1;i<=p;++i)
    			{
    				for(int j=1;j<=q;++j) v[i][j][k]=read();
    			}
    		}
    		for(int i=1;i<=p;++i)
    		{
    			for(int j=1;j<=q;++j)
    			{
    				add(S,id(i,j,1),1e18+10);
    				for(int k=1;k<=r;++k) add(id(i,j,k),id(i,j,k+1),v[i][j][k]);
    				add(id(i,j,r+1),T,1e18+10); 
    			}
    		}
    		for(int i=1;i<=p;++i)
    		{
    			for(int j=1;j<=q;++j)
    			{
    				for(int k=0;k<4;++k)
    				{
    					int x=i+fx[k],y=j+fy[k];
    					if(!in(x,y)) continue;
    					for(int l=d+1;l<=r+1;++l) add(id(i,j,l),id(x,y,l-d),1e18+10);
    				}
    			}
    		}
    		int ans=0;
    		while(bfs()) ans+=dfs(S,1e18+10);
    		printf("%lld
    ",ans);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    

    Review

    限制可以转化成网络图上面的必经边,然后直接连 (inf) 边就好了

  • 相关阅读:
    【洛谷4758】[CERC2014] Mountainous landscape(线段树维护凸壳)
    【UOJ671】【UNR #5】诡异操作(线段树+位运算)
    【洛谷5435】基于值域预处理的快速 GCD
    【CF1267G】Game Relics(期望)
    【洛谷8100】[USACO22JAN] Counting Haybales P(DP)
    【CFGym102586L】Yosupo's Algorithm(分治+二维数点)
    【洛谷3934】[Ynoi2016] 炸脖龙 I(奈芙莲树)
    【UOJ660】【IOI2021】candies(线段树)
    【CF1601F】Two Sorts(Meet in Middle)
    【CF1017G】The Tree(线段树)
  • 原文地址:https://www.cnblogs.com/yspm/p/13116324.html
Copyright © 2020-2023  润新知