暂无链接
叠盒子
【问题描述】
企鹅豆豆家里有很多空盒子,非常占地方。每个盒子的长和宽分别为 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;
题解
考场上各位大佬网络流一眼秒,各种套路,只有没做过最小路径覆盖的蒟蒻瑟瑟发抖。本来觉得这个盒子一层层缩小的操作和水流挺像的,一直在想怎么把盒子大小当成流量放在边上,建一波图,又不会限制每个盒子只能用一次。然后出题人出给暴力的数据还少了一个点,实际上只有 的暴力分。。。
其实对于盒子的限制是通过流量来的,源点向每个盒子连流量为 的边。为了处理盒子间的嵌套,需要拆点,我们把每个盒子拆成出点和入点,每个盒子的入点向它能套住的盒子的出点连边。最后每个盒子再向汇点连容量为 ,费用为盒子大小的边,样例建图如下:
这样,最后流到汇点的最大流的费用就是被套住的盒子的面积,我们用总面积减掉费用得到了答案。
代码
#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();}