题目
一条很长的街道上有 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 个房子处倒垃圾。
解题思路
题目要求求每户离垃圾桶的最短距离之和;
所以我们首先需要求出每户距离垃圾的最短距离;
我们可以先从左往右遍历,找距离该垃圾桶最近的左垃圾桶;再从右往左遍历,找距离该垃圾桶最近的右垃圾桶;然后求出其最近垃圾桶的距离;
注意:
- 当前位置左边或者右边可能不存在垃圾桶,需要将其距离设为最大;
- 当前位置有垃圾桶时,距离为 0,若数组为循环利用,记得初始化为 0;
- 时间复杂度为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;
}