NKOJ-4190 鞋店 <2017信息学夏令营第1场 B题>

17 篇文章 0 订阅

B鞋店
时间限制 : - MS 空间限制 : 265526 KB
评测说明 : 1s
问题描述

    何老板经营的鞋店有n双鞋。每双鞋都有一定价格和尺码,对于第i双鞋,Ci表示它的价格,Si表示它的尺码。每双鞋的尺码都不相同。
    店里来了m个客户,每个客户都想买一双鞋,其中第i个客户有Di块钱,他的脚的尺码是Li。每个客户都愿意买尺码跟他脚相同或者大一码的鞋子。也就是对于j号鞋子,若满足(Cj<=Di)&&(Li==Sj||Li==Sj-1),i号客户就愿意买j号鞋。
    贪婪的何老板希望卖出去的鞋子的总价尽可能高,请你帮他算算,他最多能卖出多少钱?
    注意:一个顾客最多买一双鞋,一双鞋最多卖给一个顾客

输入格式
第一行,一个整数n
接下来n行,每行两个整数Ci和Si,表示一双鞋子的价格和尺码
接下来一行,一个整数m
接下来m行,每行两个整数Di和Li,表示一个客户的钱和他的脚的尺码

输出格式
一行,一个整数,表示能卖出去的最大总额。

样例输入 1
3
10 1
30 2
20 3
2
20 1
20 2

样例输出 1
30

样例输入 2
3
10 4
20 5
30 6
2
70 4
50 5

样例输出 2
50

提示
对于30%的数据1<=n,m<=100
对于100%的数据:
**1<=n<=5000
1<=m<=10000**
1<=Ci,Si,Di,Li<=1000000000

这道题目考试的时候只得了七十分

仔细反思了一下,方法做法都是对的
错的原因就是
做了各种花里胡哨的优化

没错这道题目数据很大
但是你除了输入优化之外

什么都不要优化!!

有一句说一句,这个顾客好傻啊,店主给啥他就买啥…

题解

这道题目其实不难想
由于一双鞋只能对应一个人,所以就是求最大匹配

但这道题目还有一个条件,就是要求收入最高
那么换言之就是求边权最大的最大匹配嘛

但是最大匹配是没有边权的,怎么办呢

题目给了一个很重要的信息,就是老板很贪心
所以就贪心

先按照价格给鞋子排序
然后从最贵的鞋开始匹配
只要匹配上了,就把这双鞋给卖出去
最后得到的和就是结果

解惑

①是否存在不是最大匹配却是最大解的情况呢?
不存在的

我们假设已经跑出了一个最大匹配,并且这个匹配当中不包含可以卖出的最贵的鞋子
那么可以买最贵的鞋子的那个人一定在最大匹配当中
我们就把那个人的鞋子换成了最贵的鞋子

假如可以买最贵的鞋子的那个人不在这个匹配当中
那么这个匹配一定不是最大匹配
因为你还可以加一条边(这个人买最贵的鞋子)

②数组开多大呢
由于最多有5000双鞋,10000个人
那么最大的情况就是10000个人每个人都能匹配到每一双鞋
就是最多的边数=5000*10000

至于鞋子什么的
就是5000双
人就不用存进数组里头了

③如何对鞋子进行排序呢(毕竟鞋子含有鞋码和钱两个参数)
结构体排序
详情见代码

附上代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

inline int input()
{
    char c=getchar();int o;
    while(c>57||c<48)c=getchar();
    for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;
    return o;
}

struct buy{int mon,size;}shoe[12345];//结构体
bool comp(buy a,buy b){return a.mon>b.mon;}//结构体排序函数

long long res=0;//结果可能超int,所以用long long
int n,m;
int went[12345],fath[12345];
int all=0,star[56780000],ent[56780000],nxt[56780000];

bool find(int s,int t)//最大匹配,用第二个变量t避免大规模高次数的memset
{
    int bian,e;
    for(bian=star[s],e=ent[bian];bian;bian=nxt[bian],e=ent[bian])
    if(went[e]!=t)
    {
        went[e]=t;
        if(!fath[e]||find(fath[e],t))
        {
            fath[e]=s;
            return 1;
        }
    }
    return 0;
}

void add(int s,int e)
{
    nxt[++all]=star[s];
    star[s]=all;
    ent[all]=e;
}

int main()
{
    int mon,size;
    n=input();
    for(int i=1;i<=n;i++)shoe[i].mon=input(),shoe[i].size=input();
    sort(shoe+1,shoe+n+1,comp);
    m=input();
    for(int a=1;a<=m;a++)
    {
        mon=input();size=input();
        for(int i=1;i<=n;i++)
            if((shoe[i].size==size||shoe[i].size==size+1)&&shoe[i].mon<=mon)
                add(i,a);
    }
    for(int i=1;i<=n;i++)if(find(i,i))res+=shoe[i].mon;//由于已经排过序,所以此处是从贵的鞋开始匹配
    printf("%lld",res);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值