BZOJ3144 切糕

题目描述

经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B。出于美观考虑,小 A 希望切面能尽量光滑且和谐。于是她找到你,希望你能帮她找出最好的切割方案。出于简便考虑,我们将切糕视作一个长 P、宽 Q、高 R 的长方体点阵。我们将位于第 z层中第 x 行、第 y 列上(1≤x≤P, 1≤y≤Q, 1≤z≤R)的点称为(x,y,z),它有一个非负的不和谐值 v(x,y,z)。一个合法的切面满足以下两个条件:与每个纵轴(一共有 P*Q 个纵轴)有且仅有一个交点。即切面是一个函数 f(x,y),对于所有 1≤x≤P, 1≤y≤Q,我们需指定一个切割点 f(x,y),且 1≤f(x,y)≤R。切面需要满足一定的光滑性要求,即相邻纵轴上的切割点不能相距太远。对于所有的 1≤x,x’≤P 和 1≤y,y’≤Q,若|x-x’|+|y-y’|=1,则|f(x,y)-f(x’,y’)| ≤D,其中 D 是给定的一个非负整数。 可能有许多切面f 满足上面的条件,小A 希望找出总的切割点上的不和谐值最小的那个。

解析:

其实题目描述那么长,他的意思不过是:有很多根杆子,每根都有R个点,每个点有一个权值,在每根上选一个点,相邻杆子的点的高度差不超过D,求最小权值和。这道题的建模比较神奇,考虑最小割。一共P*Q*R个点,从P*Q个R-1层到R层的点连边代表选择这一层的权值;加一个0层,S到0层连INF,R层到T连INF,相邻相差超过D的层连INF这样最小割(最大流)就代表每个方格必须选一个层,相邻方格差不超过D的最小代价。怎么想到的这么建的,其实很简单,因为每根只能选一个点,一定要把每根上两点之间连上边权,但原图上的边是不够把R条边插进去的,自然而然就想到再建一层。考虑到距离限制,我们让相邻相差超过D的层连INF,这样这条边就割不掉啦,然后就解决啦~。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 1e9
#define MAXN 300005
using namespace std;
queue<int> q;
struct node
{
    int from,to,remain,next;
}e[MAXN*10];
int e_num=-1,point[MAXN];
int deep[MAXN],cur[MAXN];
bool vis[MAXN];
int s,t,ans,n,m;
int P,R,Q,D;
inline int get()
{
    int x=0,p=1;char c;
    c=getchar();
    while (c<'0'||c>'9') {if (c=='-') p=-1;c=getchar();}
    while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*p;
}
inline void add(int from,int to,int remain)
{
    ++e_num;
    e[e_num].from=from;
    e[e_num].to=to;
    e[e_num].remain=remain;
    e[e_num].next=point[from];
    point[from]=e_num;
}
bool bfs(int from,int to)
{
    memset(deep,0x7f,sizeof(deep));
    memset(vis,0,sizeof(vis));
    for (int i=0;i<=t;i++)
        cur[i]=point[i];
    deep[from]=0;
    vis[from]=1;
    q.push(from);
    while (!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        for (int i=point[u];i!=-1;i=e[i].next)
            if (deep[e[i].to]>inf&&e[i].remain)
            {
                deep[e[i].to]=deep[u]+1;
                if (!vis[e[i].to])
                {
                    q.push(e[i].to);
                    vis[e[i].to]=true;
                }
            }
    }
    return deep[to]<inf;
}
int dfs(int from,int to,int limit)
{
    int f,flow=0;
    if (!limit) return 0;
    if (from==to) return limit;
    for (int i=cur[from];i!=-1;i=e[i].next)
    {
        cur[from]=i;
        if (deep[e[i].to]==deep[from]+1&&(f=dfs(e[i].to,to,min(limit,e[i].remain))))
        {
            flow+=f;
            limit-=f;
            e[i].remain-=f;
            e[i^1].remain+=f;
            if (!limit) break;
        }
    }

    return flow;
}
void dinic()
{
    while (bfs(s,t))
        ans+=dfs(s,t,inf);
}
void addedge(int x,int y,int z)
{
    add(x,y,z);
    add(y,x,0);
}
int calc(int x,int y,int z)
{
    return (x-1)*P*Q+(y-1)*Q+z;
}
int main()
{
    int x,cnt=0;
    memset(point,-1,sizeof(point));
    P=get();Q=get();R=get();D=get();
    s=0;t=(P+1)*(Q+1)*(R+1)+100;

    for (int i=1;i<=R;i++)
        for (int j=1;j<=P;j++)
        {
            for (int k=1;k<=Q;k++)
            {
                if (i==1) addedge(s,calc(1,j,k),inf);
                if (i==R) addedge(calc(R+1,j,k),t,inf);
                x=get();
                addedge(calc(i,j,k),calc(i+1,j,k),x);
            } 
        }
    for (int i=D+1;i<=R;i++)
        for (int j=1;j<=P;j++)
            for (int k=1;k<=Q;k++)
            {
                if (j+1<=P)
                    addedge(calc(i,j,k),calc(i-D,j+1,k),inf);
                if (j-1>=1)
                    addedge(calc(i,j,k),calc(i-D,j-1,k),inf);
                if (k+1<=Q)
                    addedge(calc(i,j,k),calc(i-D,j,k+1),inf);
                if (k-1>=1)
                    addedge(calc(i,j,k),calc(i-D,j,k-1),inf);
            }
    dinic();
    printf("%d",ans);
}

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值