[NOIP2017模拟]放盒子

2017.10.19 T3 1994

样例数据
输入

3
1 1
1 2
2 1

输出

4

分析:用纯粹的贪心肯定是不行的,我们要进行有调理的贪心,这里就要用到一种算法——匈牙利算法!大家可以看Dark_Scope的博客,私以为是世界上讲的最好的匈牙利算法了,通俗易懂!我们要想盒子占地面积尽量小,就要利用匈牙利算法的思想尽量把盒子嵌在另外的盒子里,最后达到嵌套最多的的盒子的目的。
建图的话就是左边把所有盒子当成boy,右边又把所有盒子当成girl(Dark_Scope的说法哈哈哈哈),让尽量多的boy找到girl也就是让尽量多的盒子能嵌套在其他盒子里,由于我们把盒子面积从大到小排序了,所以优先把面积大的盒子嵌套了,根据题意一个盒子只能嵌套一个盒子,相当于充分利用了嵌套这个盒子的大盒子,而对后面的小盒子,这个被嵌套了的盒子依然可以用来嵌套它们所以不会出现选择小盒子比选择大盒子优的情况,所以得到答案肯定是能嵌套最大面积(最优情况)。
P.S. 也可以用费用流求解,建图也是这么建(只是加上超级源点、汇点),跑最大费用流。

代码
匈牙利算法板子

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

struct node{
    int x,y;
}box[205];
int n,ans,belong[205];
bool line[205][205],visit[205];

bool comp(const node &a,const node &b)
{
    return a.x*a.y>b.x*b.y;
}

bool find(int x)
{
    for(int i=1;i<x;++i)
    {
        if(line[x][i]==true&&!visit[i])
        {
            visit[i]=true;
            if(!belong[i]||find(belong[i]))
            {
                belong[i]=x;
                return true;
            }
        }
    }

    return false;
}

int main()
{
    freopen("box.in","r",stdin);
    freopen("box.out","w",stdout);

    n=getint();
    for(int i=1;i<=n;++i)
    {
        box[i].x=getint();
        box[i].y=getint();
    }

    sort(box+1,box+n+1,comp);//盒子按面积大小单调递减排序

    for(int i=1;i<=n;++i)
    {
        ans+=box[i].x*box[i].y;//算出总占地面积
        for(int j=1;j<=n;++j)
        {
            if(box[i].x>=box[j].x&&box[i].y>=box[j].y)//建边,表示盒子j能嵌在盒子里
                line[j][i]=true;
        }
    }

    for(int i=2;i<=n;++i)//匈牙利算法
    {
        memset(visit,false,sizeof(visit));
            if(find(i))//如果i能找到盒子来嵌套,那么这个盒子就不占地了
                ans-=box[i].x*box[i].y;
    }

    cout<<ans<<'\n';
    return 0;
}

本题结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值