AcWing 4114. 垃圾桶 c++和Java实现

18 篇文章 0 订阅
17 篇文章 0 订阅

题目

一条很长的街道上有 N 个房子。

第一个房子在位置 1,第二个房子在位置 2,以此类推。

任意一对房子 i 和 j 之间的距离为 |i−j|。

一些房子的位置处有垃圾桶。

每个房子的主人都要倒垃圾。

如果自己房子前面有垃圾桶,则无需移动,直接倒垃圾即可。

如果自己房子前面没有垃圾桶,则前往距离自己最近的垃圾桶处倒垃圾,如果这样的垃圾桶不唯一,则任意前往一个即可。

请计算,所有房子的主人倒垃圾需要行走的总距离之和。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 N。

第二行包含一个长度为 N 的 01 字符串,第 i 个字符如果为 1,则表示第 i 个房屋门前有垃圾桶,如果为 0,则表示第 i 个房屋门前没有垃圾桶。

输出格式
每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y,其中 x 为组别编号(从 1 开始),y 为所有房子的主人倒垃圾需要行走的总距离之和。

数据范围
1 ≤ T ≤ 100,
1 ≤ N ≤ 5×105,
字符串中至少包含一个 1。

输入样例:

2
3
111
6
100100

输出样例:

Case #1: 0
Case #2: 5

样例解释
对于 Case 1,每个房子门前都有垃圾桶,所以大家都不用移动。

对于 Case 2,第 1,4 个房子的门前有垃圾桶,这两家主人不用移动,第 2 个房子的主人去第 1 个房子处倒垃圾,第 3,5,6 个房子的主人去第 2 个房子处倒垃圾。

解题思路

题目要求求每户离垃圾桶的最短距离之和;

所以我们首先需要求出每户距离垃圾的最短距离;

我们可以先从左往右遍历,找距离该垃圾桶最近的左垃圾桶;再从右往左遍历,找距离该垃圾桶最近的右垃圾桶;然后求出其最近垃圾桶的距离;

注意:

  1. 当前位置左边或者右边可能不存在垃圾桶,需要将其距离设为最大;
  2. 当前位置有垃圾桶时,距离为 0,若数组为循环利用,记得初始化为 0;
  3. 时间复杂度为O(n),使用 c++ 时建议使用 scanf() 和 printf() ,防止因输入输出开销过大导致 TLE。

AC代码

Java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
	
	public static void main(String[] args) throws IOException {
		InputReader in = new InputReader(System.in);
		PrintWriter out = new PrintWriter(System.out);
		
		int t = in.nextInt();
		
		int n = 0;
		char[] ch;
		
		int index = -1;	// 前一个有垃圾桶的位置
		long res = 0;	// 总路程
		
		for(int i = 1; i <= t; i++) {
			n = in.nextInt();
			ch = in.next().toCharArray();
			
			int[] l = new int[n];
			int[] r = new int[n];
			
			index = -1;
			// 从左往右找
			for(int j = 0; j < n;  j++) {
				if(ch[j] == '0') {	// 当前位置没有垃圾桶
					l[j] = j - index;	// 计算距离
					if(index == -1) l[j] = Integer.MAX_VALUE;	// 当前位置的左边没有出现过垃圾桶
				}
				else index = j;	// 更新最左边垃圾桶的位置
			}
			
			index = n;
			// 从右往左找
			for(int j = n - 1; j >= 0; j--) {	
				if(ch[j] == '0') {	// 当前位置没有垃圾桶
					r[j] = index - j;	// 计算距离
					if(index == n) r[j] = Integer.MAX_VALUE;	// 当前位置的右边没有出现过垃圾桶
				}
				else index = j;	// 更新最右边垃圾桶的位置
			}
			
			res = 0;
			for(int j = 0; j < n; j++) {
				res += Math.min(l[j], r[j]);	// 取最近的垃圾桶
			}
			
			out.println("Case #" + i + ": " + res);
		}
		
		out.flush();
	}
	
	public static class InputReader {
		BufferedReader reader;
		StringTokenizer tokenizer;
		
		public InputReader(InputStream in) {
			reader = new BufferedReader(new InputStreamReader(in));
		}
		
		public String next() throws IOException {
			while(tokenizer == null || !tokenizer.hasMoreTokens()) {
				tokenizer = new StringTokenizer(reader.readLine());
			}
			return tokenizer.nextToken();
		}
		
		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}
	}

}

c++

#include<bits/stdc++.h>

using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 5e5 + 10;
int l[N];
int r[N];
char s[N];

int main()
{
    int t = 0;
    scanf("%d", &t);

    int n = 0;

    int index = -1; // 前一个有垃圾桶的位置
    long res = 0;   // 总路程


    for(int i = 1; i <= t; i++)
    {
        scanf("%d%s", &n, s);

        index  = -1;
        // 从左往右找
        for(int j = 0; j < n; j++)
        {
            if(s[j] == '0') // 当前位置没有垃圾桶
            {
                l[j] = j - index;   // 计算距离
                if(index == -1) l[j] = INF; // 当前位置的左边没有出现过垃圾桶
            }
            else
            {
                l[j] = 0;   // 当前位置有垃圾桶
                index = j;  // 更新最左边垃圾桶的位置
            }
        }

        index = n;
        // 从右往左找
        for(int j = n - 1; j >= 0; j--)
        {

            if(s[j] == '0') // 当前位置没有垃圾桶
            {
                r[j] = index - j;   // 计算距离
                if(index == n) r[j] = INF;  // 当前位置的右边没有出现过垃圾桶
            }
            else
            {
                r[j] = 0;   // 当前位置有垃圾桶
                index = j;  // 更新最右边垃圾桶的位置
            }
        }

        res = 0;
        for(int j = 0; j < n; j++) res += min(l[j], r[j]);  // 取最近的垃圾桶

        printf("Case #%d: %ld\n", i, res);
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值