[HNOI2013]切糕

首先这个切面把长方体切割成了两部分,显然要去考虑最小割。

如果没有光滑度的限制,把点看成边,直接建一个立体图,跑最小割即可。

加上这个限制后,带来的不同就是,如果两个点,|f(x1,y1)-f(x2,y2)|>=d,这两条边即使被割掉了,s和t依然要保证连通性不受影响。

考虑用连inf边来解决这个问题。注意想清楚连边的方向。

如果是由底层向上层连边的话,会导致如果反着走的话,及时采取了正确的割边方案,st依然会联通。

考虑反向连边,即由高层向底层。首先这样连显然不会产生刚才那种玄学情况。而且这样也确实满足了合法的割边,st一定不连通。非法的割边一定st不受影响。
例如下图:

在上图中,割掉2->4和3->5也是合法的方案,然而3->6这条边的存在依然影响着s-t连通性。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdlib>
#include<algorithm>
#define N 110000
#define M 440000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
    char ch=0;
    int x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
struct edge
{
    int to,nxt,w;
}e[M];
int num,head[N];
inline void add(int x,int y,int z)
{
    e[++num]=(edge){y,head[x],z};head[x]=num;
    e[++num]=(edge){x,head[y],0};head[y]=num;
}
queue<int>q;
int n,m,s,t,cur[N],dep[N];
bool bfs()
{
    for(int i=0;i<=t;i++)dep[i]=0,cur[i]=head[i];
    dep[s]=1;q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i!=-1;i=e[i].nxt)
        {
            int to=e[i].to;
            if(!dep[to]&&e[i].w)
            {
                dep[to]=dep[x]+1;
                q.push(to);
            }
        }
    }
    return dep[t];
}
int dfs(int x,int flow)
{
    if(x==t)return flow;
    for(int i=cur[x];i!=-1;i=e[i].nxt)
    {
        cur[x]=i;
        int to=e[i].to;
        if(dep[to]==dep[x]+1&&e[i].w)
        {
            int w=dfs(to,min(flow,e[i].w));
            if(w)
            {
                e[i].w-=w;
                e[i^1].w+=w;
                return w;
            }
        }
    }
    return 0;
}
int dinic()
{
    int maxflow=0;
    while(bfs())maxflow+=dfs(s,inf);
    return maxflow;
}
int times,id[50][50][50];
int main()
{
	int a=read(),b=read(),c=read(),d=read();
	num=-1;memset(head,-1,sizeof(head));
	for(int k=0;k<=c;k++)
	for(int i=1;i<=a;i++)
	for(int j=1;j<=b;j++)
	id[k][i][j]=++times;
	for(int k=1;k<=c;k++)
	for(int i=1;i<=a;i++)
	for(int j=1;j<=b;j++)
	{
		add(id[k-1][i][j],id[k][i][j],read());
		if(k+d<=c)
		{
			if(i!=1)add(id[k+d][i-1][j],id[k][i][j],inf);
			if(i!=a)add(id[k+d][i+1][j],id[k][i][j],inf);
			if(j!=1)add(id[k+d][i][j-1],id[k][i][j],inf);
			if(j!=b)add(id[k+d][i][j+1],id[k][i][j],inf); 
		}
	}
	s=times+1;t=times+2;
	for(int i=1;i<=a;i++)
	for(int j=1;j<=b;j++)
	{
		add(s,id[0][i][j],inf);
		add(id[c][i][j],t,inf);
	}
	printf("%d\n",dinic());
	return 0;
}
posted @ 2018-12-08 18:37  Creed-qwq  阅读(115)  评论(0编辑  收藏  举报