您的位置:首页 > 其它

[NOIP模拟][匈牙利算法][费用流]放盒子

2017-10-19 20:46 239 查看
题目描述:

题目大意:给出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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: