贪心——Cinema Cashier

Cinema Cashier

题面翻译

输入第一行为两个整数 N , K N,K N,K,表示一个大小为 K 2 K^2 K2 的电影院,会来 N N N 波人,相同一波的人必须坐在同一排。

输入第二行有 N N N 个数,表示每波的人数。

定义中心点 ( x c , y c ) , x c = ⌈ k 2 ⌉ , y c = ⌈ k 2 ⌉ (x_c,y_c),x_c=\lceil\frac{k}{2}\rceil,y_c=\lceil\frac{k}{2}\rceil (xc,yc),xc=2k,yc=2k,每个人的花费为 ∣ x − x c ∣ + ∣ y − y c ∣ |x-x_c|+|y-y_c| xxc+yyc,要求总花费最少。如果总花费一样,尽量向靠左靠前的位置坐。

如果坐不下,输出 − 1 -1 1;否则,输出每一波人所在的行以及所在的列的起始和终止位置。

题目描述

All cinema halls in Berland are rectangles with K K K rows of K K K seats each, and K K K is an odd number. Rows and seats are numbered from 1 1 1 to K K K . For safety reasons people, who come to the box office to buy tickets, are not allowed to choose seats themselves. Formerly the choice was made by a cashier, but now this is the responsibility of a special seating program. It was found out that the large majority of Berland’s inhabitants go to the cinema in order to watch a movie, that’s why they want to sit as close to the hall center as possible. Moreover, a company of $ M $ people, who come to watch a movie, want necessarily to occupy $ M $ successive seats in one row. Let’s formulate the algorithm, according to which the program chooses seats and sells tickets. As the request for $ M $ seats comes, the program should determine the row number $ x $ and the segment $ [y_{l},y_{r}] $ of the seats numbers in this row, where $ y_{r}-y_{l}+1=M $ . From all such possible variants as a final result the program should choose the one with the minimum function value of total seats remoteness from the center. Say, — the row and the seat numbers of the most “central” seat. Then the function value of seats remoteness from the hall center is . If the amount of minimum function values is more than one, the program should choose the one that is closer to the screen (i.e. the row number $ x $ is lower). If the variants are still multiple, it should choose the one with the minimum $ y_{l} $ . If you did not get yet, your task is to simulate the work of this program.

输入格式

The first line contains two integers $ N $ and $ K $ ( $ 1<=N<=1000,1<=K<=99 $ ) — the amount of requests and the hall size respectively. The second line contains $ N $ space-separated integers $ M_{i} $ from the range $ [1,K] $ — requests to the program.

输出格式

Output $ N $ lines. In the $ i $ -th line output «-1» (without quotes), if it is impossible to find $ M_{i} $ successive seats in one row, otherwise output three numbers $ x,y_{l},y_{r} $ . Separate the numbers with a space.

样例 #1

样例输入 #1

2 1
1 1

样例输出 #1

1 1 1
-1

样例 #2

样例输入 #2

4 3
1 2 3 1

样例输出 #2

2 2 2
1 1 2
3 1 3
2 1 1

思路(借鉴)

要让下面的式子最小,我们可以尽可能让一批人都挤在一起。

因此我们可以枚举每一批人(就连续的坐在一起),看看什么时候这个值最小,然后记录下来,最终输出。

为什么可以这么想呢?因为我们看这个式子,特别像曼哈顿距离的公式,这样我们转化成几何图形可以知道,分散的点的曼哈顿距离最小肯定是每个点都集合在一起(连续性)。

  • 细节1:我们得用st数组来存储位置是否被占用。
  • 细节2:题目要求如果有解,则输出三个整数,那么我们在遍历的时候,也应该按照这三个整数的顺序来,就:先遍历行,再遍历列,最后再遍历列的连续范围。当遍历完列的连续范围时,我们就得更新最值。

这道题给我的启示:当数据范围大的时候,我们不妨去想想贪心、模拟的思路来做题目。

代码( O ( n k 3 ) O(nk^3) O(nk3)

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1010;

int w[N];
bool st[N][N];
int n,k;
int ans;

int main(){
    cin>>n>>k;
    
    //核心坐标
    int x=(k+1)/2,y=(k+1)/2;
    
    for(int i=1;i<=n;i++)cin>>w[i];
    
    for(int u=1;u<=n;u++){
        int xx=1,yy=1;//答案行,答案列
        ans=2e9;
        //求最优的位置
        for(int i=1;i<=k;i++){//行
            for(int j=1;j<=k-w[u]+1;j++){//列
                bool f=false;
                int t=0;
                
                for(int l=j;l<=j+w[u]-1;l++){//列的范围
                    if(st[i][l]){
                        f=true;
                        break;
                    }else{
                        t+=abs(i-x)+abs(l-y);
                    }
                }
                
                if(!f&&ans>t){
                    ans=t;
                    xx=i;
                    yy=j;
                }
            }
        }
        
        //输出最优的
        if(ans==2e9)puts("-1");
        else{
            cout<<xx<<" "<<yy<<" "<<(yy+w[u]-1)<<endl;
            for(int i=yy;i<=yy+w[u]-1;i++)st[xx][i]=true;
        }
    }
    
    return 0;
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值