1 条题解

  • 0
    @ 2025-5-22 13:45:17

    市场摊位问题题解

    题目分析

    市场中有NN个现有摊位,新摊位需选择位置LL(现有摊位LL之后,1L<N1 \leq L < N)和价格PP,使得预期收入最大化。买家分两种方向行走(左→右、右→左),按规则选择价格最低的摊位(同价选最近)。需结合各KK值(经过KK个摊位后返回)的买家比例BKB_K计算收入。

    算法思路

    1. 价格候选生成
      最优价格通常出现在现有价格的邻近值(如略低于某摊位价格)。因此,生成所有现有价格的原值及原值减1作为候选价格,去重后排序。

    2. 枚举所有可能位置和价格
      遍历所有可能的新摊位位置LL1L<N1 \leq L < N)和候选价格PP,计算每个组合的预期收入。

    3. 收入计算(countcount函数)
      对每个位置LL和价格PP,模拟左右两个方向的买家行为:

      • 左→右方向:买家经过KK个摊位(K=1NK=1 \sim N),记录前KK个摊位的最低价格摊位。若新摊位是最低且最近,则累加对应BKB_K的比例。
      • 右→左方向:类似,买家从右向左经过KK个摊位,同样统计新摊位被选中的比例。
        总收入为价格PP乘以总比例(左右各占50%)。

    代码关键步骤解析

    1. 输入处理与价格候选生成
    • 候选价格生成逻辑:通过现有价格的原值及原值减1,覆盖可能的最优价格(如略低于某摊位价格以吸引买家)。
    • 去重排序:确保候选价格唯一且有序,减少重复计算。
    2. 收入计算函数countcount
    • 插入新摊位:将新摊位插入到位置kk(原摊位kk之后),调整数组顺序。
    • 左→右统计:遍历前KK个摊位(K=1NK=1 \sim N),记录最低价格摊位。若新摊位是最低且最近,则累加对应BKB_K的比例。
    • 右→左统计:反向遍历,逻辑类似,注意KK值与BKB_K的映射关系(如右→左经过KK个摊位对应BnK+1B_{n-K+1})。
    3. 枚举所有位置和价格,选择最优解
    • 双重循环枚举:遍历所有可能的位置LL和候选价格PP
    • 最优解选择:优先收入最大;若收入相同,选LL最小;若LL相同,选PP最小。

    示例验证(输入数据1)

    输入:

    5  
    37 34 34 35 33  
    10 20 30 30 10  
    
    • 候选价格:现有价格为37373434343435353333,生成候选价格为3636373733333434333334343434353532323333。去重排序后为323233333434353536363737
    • 枚举位置L=2L=2(原摊位2之后),价格P=33P=33
      • 左→右方向:买家经过K=15K=1 \sim 5个摊位。插入新摊位后,价格数组为[37,34,33,34,35,33][37,34,33,34,35,33]。前KK个摊位的最低价格摊位可能为新摊位(位置2),累加对应BKB_K的比例。
      • 右→左方向:反向遍历时,新摊位同样可能被选中,累加对应比例。
      • 总收入为33×33 \times总比例,为最大收入。

    标程

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<string>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<list>
    #include<iostream>
    #include<map>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define Max 110
    int max(int a,int b)
    {
    	return a>b?a:b;
    }
    int min(int a,int b)
    {
    	return a<b?a:b;
    }
    int n;
    int pri[210],price[210],p[210],rat[210];
    int count(int k,int p)
    {
        int i,tmp;
        for(i=0;i<k;i++)
            pri[i]=price[i];
        for(i=k;i<n;i++)
            pri[i+1]=price[i];
        pri[k]=p;
        int minx=inf,cnt=0;
        for(i=0;i<n;i++)
        {
            if(pri[i]<=minx)
            {
                minx=pri[i];
                tmp=i;
            }
            if(tmp>k)
                break;
            if(tmp==k)
                cnt+=rat[i];
        }
        minx=inf;
        for(i=n;i>0;i--)
        {
            if(pri[i]<=minx)
            {
                minx=pri[i];
                tmp=i;
            }
            if(tmp<k)
                break;
            if(tmp==k)
                cnt+=rat[n-i];
        }
        return p*cnt;
    }
    int main()
    {
        int i,j,cnt;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d",&price[i]);
            p[2*i]=price[i]-1;p[2*i+1]=price[i];
        }
        for(i=0;i<n;i++)
            scanf("%d",&rat[i]);
        sort(p,p+2*n);
        cnt=1;
        for(i=1;i<2*n;i++)
        {
            if(p[i]>p[i-1])
                p[cnt++]=p[i];
        }
        int ans=0;
        int tmp;
        int pos=1;
        int recp=p[0];
        for(i=1;i<n;i++)
            for(j=0;j<cnt;j++)
            {
              //  printf("p %d\n",p[j]);
                tmp=count(i,p[j]);
              //  printf("i %d j %d tmp %d\n",i,j,tmp);
                if(tmp>ans)
                {
                    ans=tmp;
                    pos=i;
                    recp=p[j];
                }
            }
       // printf("ans %d\n",ans);
        printf("%d %d\n",pos,recp);
    }
    

    总结

    本题通过枚举所有可能的位置和价格,结合买家行为模拟,计算预期收入,最终选择最优解。关键在于正确模拟买家选择逻辑(最低价格、同价选最近),并高效生成候选价格以覆盖可能的最优解。代码通过预处理候选价格和双重循环枚举,确保在合理复杂度内解决问题(N100N \leq 100时可行)。

    • 1