1. 程式人生 > >洛谷 P3227 BZOJ 3144 [HNOI2013]切糕

洛谷 P3227 BZOJ 3144 [HNOI2013]切糕

str class 記得 不知道 sizeof .cn emp color edge

題目描述

經過千辛萬苦小 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)。一個合法的切面滿足以下兩個條件:

  1. 與每個縱軸(一共有 P*Q 個縱軸)有且僅有一個交點。即切面是一個函數 f(x,y),對於所有 1≤x≤P, 1≤y≤Q,我們需指定一個切割點 f(x,y),且 1≤f(x,y)≤R。

  2. 切面需要滿足一定的光滑性要求,即相鄰縱軸上的切割點不能相距太遠。對於所有的 1≤x,x’≤P 和 1≤y,y’≤Q,若|x-x’|+|y-y’|=1,則|f(x,y)-f(x’,y’)| ≤D,其中 D 是給定的一個非負整數。 可能有許多切面f 滿足上面的條件,小A 希望找出總的切割點上的不和諧值最小的那個。

//盡管洛谷上有了上面的文字題面,但是這副圖片在別的博客上那麽多見,我還是放上來吧

技術分享

輸入輸出格式

輸入格式:

第一行是三個正整數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。

輸出格式:

僅包含一個整數,表示在合法基礎上最小的總不和諧值。

輸入輸出樣例

輸入樣例#1:
2  2 2
1
6  1
6  1
2  6
2  6
輸出樣例#1:
6

說明

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

吐槽

  我為什麽最近會突然開始刷網絡流呢?因為最近在長樂一中集訓,難得美國隊長妹滋滋大佬來講課,講了一整天的網絡流,我記了差不多20頁信箋紙的筆記……(聽課時開著電腦會損失很大的,不騙你,記筆記是個很好的學習習慣啊) 那天聽得我腦力耗盡,去吃中午飯時讓同行的Neil描述成——讓他想到了一個遊戲“饑荒”。詳見……

  最近請教某些大佬時遭到了BS,RP暴漲啊,常數巨小,下面的代碼占領了洛谷的rank1~3(我交了三次嘻嘻),不開O2時正好rank20(交那三次之前)。

  真記不得這個題面玩的梗是咋回事了……好像那是我初二上學期的時候,那段時間嫦娥幾號來著還著陸在月球來著,我那晚看了CCTV三個小時的直播。記得那時日子多麽美好…………

  好了,暫停回憶吧,咳咳!開始講題——

解題思路

  一道離散變量模型裸題。妹滋滋的幻燈片上這麽說的——//不知道這樣是否違反了某些基本法,如果有請告知,我刪除

技術分享

  對於切糕這題——

技術分享

源代碼

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>

int p,q,r,D;
int cake[42][42][42]={0};

int s,t;
struct Edge{
    int next,to,c;
}e[200010];
int head[200010],cnt=2;
void add(int u,int v,int c)
{
    e[cnt]={head[u],v,c};
    head[u]=cnt++;
    e[cnt]={head[v],u,0};
    head[v]=cnt++;
}

int dis[200010]={0};
bool bfs()
{
    memset(dis,0,sizeof(dis));
    dis[s]=1;
    std::queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(e[i].c==0||dis[v]) continue;
            dis[v]=dis[u]+1;
            q.push(v);
        }
    }
    return dis[t]!=0;
}

int dfs(int u,int flow)
{
    if(flow==0||u==t) return flow;
    int flow_sum=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to,f=std::min(e[i].c,flow-flow_sum);
        if(dis[v]!=dis[u]+1||!e[i].c) continue;
        int temp=dfs(v,f);
        e[i].c-=temp;
        e[i^1].c+=temp;
        flow_sum+=temp;
        if(flow<=flow_sum) break;
    }
    if(flow_sum==0) dis[u]=-1;
    return flow_sum;
}

int dinic()
{
    int ans=0;
    while(bfs())
        while(int temp=dfs(s,0x7f7f7f7f))
            ans+=temp;
    return ans;
}

inline int id(int x,int y,int z)
{
    if(z==0) return s;
    if(z==r+1) return t;
    return (z-1)*p*q+(x-1)*q+y;
}

int main()
{
    //freopen("test.in","r",stdin);
    scanf("%d%d%d%d",&p,&q,&r,&D);
    s=p*q*r+1,t=s+1;
    for(int i=1;i<=r;i++)
        for(int j=1;j<=p;j++)
            for(int k=1;k<=q;k++)
                scanf("%d",&cake[j][k][i]);//網絡流的題輸入都很惡心,優化高維數組取值太饒了,索性不搞
    ;
    /***建圖***/
    int bh[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
    for(int i=1;i<=p;i++)
    {
        for(int j=1;j<=q;j++)
        {
            for(int k=1;k<=r;k++)
            {
                add(id(i,j,k-1),id(i,j,k),cake[i][j][k]);
                if(k>D)//四周
                {
                    int h=k-D;
                    for(int aa=0;aa<4;aa++)
                    {
                        int ii=i+bh[aa][0],jj=j+bh[aa][1];
                        if(ii>0&&ii<=p&&jj>0&&jj<=q)
                            add(id(i,j,k),id(ii,jj,h),0x7f7f7f7f);
                    }
                }
            }
            add(id(i,j,r),t,0x7f7f7f7f);
        }
    }
    printf("%d",dinic());
    return 0;
}

洛谷 P3227 BZOJ 3144 [HNOI2013]切糕