"Algorithm Competition · 300 Quick Questions" one question per day: "Sokoban"

" Algorithm Competition: 300 Quick Questions " will be published in 2024, and it is an auxiliary workbook for "Algorithm Competition" .
All questions are placed in the self-built OJ New Online Judge .
The codes are provided in C/C++, Java, and Python. The topics are mainly low-to-medium level, suitable for beginners and advanced.


" Sokoban ", link: http://oj.ecustacm.cn/problem.php?id=1819

topic description


[Title description] In front of a box of height H, there is an obstacle of length and height N.
  There is a continuous gap in each column of obstacles, and the gap in the i-th column is from the l-th unit to the h-th unit (counting from the bottom starts from 0).
  Now please clear out a channel with a height of H so that the box can be pushed out directly.
  Please output the minimum obstacle area that needs to be cleared.
  The following figure shows the obstacle in the sample, the length and height are both 5, and the height of the box is 2. There is no need to consider that boxes will fall into certain pits. At least two units of obstacles need to be removed to create a path of height 2.
insert image description here

【Input format】 Input the first row of two positive integers N and H, indicating the size of the obstacle and the height of the box, 1≤H≤N≤1000000.
  The next N lines, each line contains two integers li and hi, indicating the range of the i-th column gap, 0≤li≤hi<N.
【Output Format】 Output a number to represent the answer.
【Input sample】

5 2
2 3
1 2
2 3
1 2
2 3

【Example of output】

2

answer

  The height of the box is H, check the consecutive H lines in the obstacle, and see which H line needs to clear the least obstacles, or which H line has the most blanks. In the input example, there are 5 lines of obstacles. The number of blanks in these 5 lines is (0, 2, 5, 3, 0) from the bottom to the top, and the 2 lines (5, 3) have the most blanks, which is 5+3=8. The number of obstacles to be removed is N×H-8=5×2-8=2.
  The obstacle is represented by the array a[], and a[i] is the number of blanks in the i-th line of the obstacle. The topic is abstracted as: a[] is N integers, find consecutive H integers from a[], and their sum is required to be the largest.
  Consider using the brute force method to solve it first.
  (1) If you use the brute force method to sum the H integers in a[] sequentially from left to right, find the largest sum, the total calculation amount is O(NH), and timeout.
  (2) It is also necessary to pay attention to the input problem. The title gives the number of blanks by column, the number of blanks that needs to be converted to rows. If it is simply converted, the amount of calculation is too large. For example, the blank position in column 1 of the example is (2, 3), and a[2]++ and a[3]++ need to be assigned. There are H blanks in one column, the a[] array needs to be assigned H times, and the total calculation amount of N columns is O(NH), timeout.
  This question is optimized with difference and prefix sum.
  (1) Process the input with a differential. Line 9 of the following code reads the starting position li and end position hi of a column, the code lines 10 and 11 are input to d[], and d[] is the difference of a[]. The amount of calculation is only O(N).
  (2) Use the prefix sum to find the interval sum. Line 14 uses d[] to find a[]; Line 16 calculates the prefix and sum[] of a[]; Lines 18 and 19 find the largest interval sum. The amount of calculation is only O(N). .
[Notes] Familiarize yourself with the application of difference and prefix sum through this question.

C++ code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
ll d[N], a[N], sum[N];
int main(){
    
    
    int n, h;   scanf("%d%d",&n,&h);
    for(int i = 1; i <= n; i++) {
    
    
        int li, hi;     scanf("%d%d",&li,&hi);       //本题n≤1000000,用scanf输入比cin快
        d[li]++;                                             //可替换为  sum[li]++;
        d[hi+1]--;                                           //可替换为  sum[hi+1]--;
    }
    //用差分数组计算原数组
    for(int i = 1; i <= n; i++)  a[i] = a[i-1] + d[i-1];     //可替换为  sum[i] += sum[i-1];
    //用原数组计算前缀和数组
    for(int i = 1; i <= n; i++)  sum[i] = sum[i-1] + a[i];   //可替换为  sum[i] += sum[i-1];
    ll ans = sum[h-1];
    for(int left = 1; left+h-1 <= n; left++)
        ans = max(ans, sum[left+h-1] - sum[left-1]);
    cout << (ll)n * h - ans << endl;
    return 0;
}

java code

import java.util.*;
import java.io.*;
public class Main{
    
    
    static int N = 1_000_010;
    static long[] d = new long[N], a = new long[N], sum = new long[N];
    public static void main(String[] args) throws Exception{
    
    
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt(), h = scan.nextInt();
        for(int i = 1; i <= n; i++) {
    
    
            int li = scan.nextInt(), hi = scan.nextInt();
            d[li]++;
            d[hi+1]--;
        }
        for(int i = 1; i <= n; i++)  a[i] = a[i-1] + d[i-1];   //用差分数组计算原数组
        for(int i = 1; i <= n; i++)  sum[i] = sum[i-1] + a[i]; //用原数组计算前缀和数组
        long ans = sum[h-1];
        for(int left = 1; left+h-1 <= n; left++)
            ans = Math.max(ans, sum[left+h-1] - sum[left-1]);
        System.out.println((long)n * h - ans);
    }
}

Python code

import sys
input=sys.stdin.readline                       #加这句后读入会快些
n, h = map(int, input().split())
d, a, sum = [0] * (n+10), [0] * (n+10), [0] * (n+10)
for i in range(1, n+1):
    li, hi = map(int, input().split())
    d[li] += 1
    d[hi+1] -= 1
for i in range(1, n+1):  a[i] = a[i-1] + d[i-1]     #用差分数组计算原数组
for i in range(1, n+1):  sum[i] = sum[i-1] + a[i]   #用原数组计算前缀和数组
ans = sum[h-1]
for left in range(1, n-h+2):  ans = max(ans, sum[left+h-1] - sum[left-1])
print(n * h - ans)

Guess you like

Origin blog.csdn.net/weixin_43914593/article/details/131730112
Recommended