题目描述:
题目大意:给出n(≤200)个盒子,第i个盒子长
xi
,宽
yi
,一个盒子可以放入长宽都大于等于它的盒子里,并且每个盒子里只能放入一个盒子(可以嵌套),嵌套的盒子的占地面积等于最外层的盒子的占地面积,求最小的占地面积之和。
样例输入:
3
1 1
1 2
2 1
样例输出:
4
题目分析:
这道题即可以用二分图最大匹配做,也可以用费用流做。
二分图匹配:我们可以把所有盒子以面积大小排序,最大的排前面,建图,两边都是一样的,即排序后的所有盒子。如果左边一个盒子能被放进右边另一个盒子,就连一条边,匹配过程,就是盒子被放入另一个盒子的过程,因为是以面积降序排序,也就是说,我们做得的最大匹配就是能够被放的盒子的最大面积和,即最大节约面积,于是用总面积减去节约的面积就是答案。正确性:一个盒子被放入另一个盒子后是不影响它自己接受其它盒子的,那么我们就尽量先让那些大盒子被放。
二分图最大匹配当然是用匈牙利做啦,如果不会,可以看一下这个人的讲解,个人认为讲解得十分通俗易懂,请戳: 趣写算法系列之–匈牙利算法
费用流:与上面类似,对上面左右两边的点建一个超级源点和超级汇点,源点和汇点连向那些盒子的代价为0,而盒子之间连边代价就是被放的那个盒子的面积,每条边的流量为1,因为盒子只能嵌套一次。然后做一遍最大费用流,得到的就是最大节约面积。
附代码:
二分图匹配:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,ans,belong[205];
bool line[205][205],vis[205];
struct node{
int x,y,w;
}box[205];
int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
bool comp(const node &a,const node &b)
{
return a.w>b.w;
}
bool find(int x)
{
for(int i=1;i<x;i++)
{
if(line[x][i]==true&&vis[i]==false)
{
vis[i]=true;
if(belong[i]==0||find(belong[i]))
{
belong[i]=x;
return true;
}
}
}
return false;
}
int main()
{
n=readint();
for(int i=1;i<=n;i++)
{
box[i].x=readint();
box[i].y=readint();
box[i].w=box[i].x*box[i].y;
}
sort(box+1,box+1+n,comp);
for(int i=1;i<=n;i++)
{
ans+=box[i].w;
for(int j=i+1;j<=n;j++)
{
if(box[i].x>=box[j].x&&box[i].y>=box[j].y)
line[j][i]=true;
}
}
for(int i=2;i<=n;i++)
{
memset(vis,false,sizeof(vis));
if(find(i)==true) ans-=box[i].w;
}
printf("%d",ans);
return 0;
}