【Hnoi2013】切糕 最大流

F.A.QsHomeDiscussProblemSetStatusRanklistContest入门OJLoginRegister捐赠本站


Notice:为保证OJ试题质量,今后添加的试题如有发现出现重复,请联系我们删除,谢谢!



Problem 3144. – [Hnoi2013]切糕

3144: [Hnoi2013]切糕

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 2021   Solved: 1090
[ Submit][ Status][ Discuss]

Description
这里写图片描述

Input

第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。

100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000。

Output

仅包含一个整数,表示在合法基础上最小的总不和谐值。

Sample Input


2 2 2

1

6 1

6 1

2 6

2 6

Sample Output


6

HINT


最佳切面的ff(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1

Source


[ Submit][ Status][ Discuss]


HOME
Back







思路:最大流,每个点向其上一层连一条容量为一的边;然后考虑限制;
这里写图片描述
每个点i向[i-D]连一条inf的边,这样保证如果选择了[i-D]以下的边,那么会导致该条道路还可以增广,所以满足了限制条件。注意输入P,Q,R的顺序。

代码:

#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()
{
    freopen("nutcake.in","r",stdin);
    freopen("nutcake.out","w",stdout);
    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);
                //    printf("%d  %d---%d  %d\n",j,k,j+1,k);    
                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);
                //    printf("%d  %d---%d  %d\n",j,k,j,k+1);
                if (k-1>=1)
                    addedge(calc(i,j,k),calc(i-D,j,k-1),inf);
            }
    dinic();
    printf("%d",ans);


}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值