[2018.07.10 T1]叠盒子

暂无链接

叠盒子

【问题描述】

企鹅豆豆家里有很多空盒子,非常占地方。每个盒子的长和宽分别为 Li,Wi,一个盒 子可以放入一个长和宽都不小于它的盒子(可以不断嵌套),注意盒子不能够旋转,Li有可能小于 Wi。嵌套完后盒子的占地面积是最外面盒子的占地面积之和。豆豆想知道最终最小的占地面积是多少?

【输入格式】

第一行一个数 N 表示盒子的个数。
接下来 N 行,每行两个正整数,表示每个盒子的长度和宽度。

【输出格式】

一行一个整数表示最终最小的占地面积。

【输入样例】

3
1 1
1 2
2 1

【输出样例】

4

【数据范围】

对于 30%的数据,N≤10;
另外 10%的数据,Li=1;
另外 10%的数据,Li≤2;
对于 100%的数据,1≤N,Li,Wi≤200;

题解

考场上各位大佬网络流一眼秒,各种套路,只有没做过最小路径覆盖的蒟蒻瑟瑟发抖。本来觉得这个盒子一层层缩小的操作和水流挺像的,一直在想怎么把盒子大小当成流量放在边上,建一波图,又不会限制每个盒子只能用一次。然后出题人出给暴力的数据还少了一个点,实际上只有 25 % 的暴力分。。。

其实对于盒子的限制是通过流量来的,源点向每个盒子连流量为 1 的边。为了处理盒子间的嵌套,需要拆点,我们把每个盒子拆成出点和入点,每个盒子的入点向它能套住的盒子的出点连边。最后每个盒子再向汇点连容量为 1 ,费用为盒子大小的边,样例建图如下:

图片1.png

这样,最后流到汇点的最大流的费用就是被套住的盒子的面积,我们用总面积减掉费用得到了答案。

代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int M=405;
struct sd{int to,fl,val;}ed[M*M*5];
int x[M],y[M],ru[M],chu[M],minf[M],dis[M],pre[M],tot,id,ans,n,top;
bool vis[M];
vector<int>mmp[M];
queue<int>dui;
void in()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d%d",&x[i],&y[i]);
}
void add(int f,int t,int fl,int val)
{
    mmp[f].push_back(id);ed[id++]=(sd){t,fl,val};
    mmp[t].push_back(id);ed[id++]=(sd){f,0,-val};
}
void build()
{
    for(int i=1;i<=n;++i)
    {
        bool flag=1;
        for(int j=i+1;j<=n;++j)if(x[i]==x[j]&&y[i]==y[j]){flag=0;break;}
        if(flag)x[++top]=x[i],y[top]=y[i];
    }n=top;
    for(int i=1;i<=n;++i)ru[i]=++tot,chu[i]=++tot;
    for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
    {
        if(i==j)continue;
        if(x[i]>=x[j]&&y[i]>=y[j])add(ru[i],chu[j],inf,0);
    }
    for(int i=1;i<=n;++i)add(0,ru[i],1,0),add(chu[i],tot+1,1,-x[i]*y[i]),ans+=x[i]*y[i];
}
bool spfa(int s,int t)
{
    fill(dis+1,dis+2+tot,inf);
    memset(vis,0,sizeof(vis));
    dui.push(s);vis[s]=1;minf[s]=inf;
    int f,to,fl,val,hh;
    while(!dui.empty())
    {
        f=dui.front(),dui.pop(),vis[f]=0;
        for(int i=mmp[f].size()-1;i>=0;--i)
        {
            hh=mmp[f][i],to=ed[hh].to,fl=ed[hh].fl,val=ed[hh].val;
            if(fl>0&&dis[to]>dis[f]+val)
            {
                dis[to]=dis[f]+val,minf[to]=min(minf[f],fl),pre[to]=hh;
                if(!vis[to])dui.push(to),vis[to]=1;
            }
        }
    }
    return dis[t]!=inf;
}
void up(int s,int t)
{
    int v=t,hh;
    while(v!=s)hh=pre[v],ed[hh].fl-=minf[t],ed[hh^1].fl+=minf[t],v=ed[hh^1].to;
    ans+=minf[t]*dis[t];
}
void ac()
{
    build();
    while(spfa(0,tot+1))up(0,tot+1);
    printf("%d",ans);
}
int main(){in();ac();}

猜你喜欢

转载自blog.csdn.net/shadypi/article/details/81003360
t1