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

来源:互联网 发布:如何升级mac os系统 编辑:程序博客网 时间:2024/06/10 15:14

题目描述:
题目大意:给出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;}
原创粉丝点击