为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接:P1354
题目描述
张兵和王武是五子棋
迷,工作之余经堂切磋棋艺。这不,这会儿又下起来了。走了一会儿,轮张兵了,对着一条线思考起来了,这条线上的棋子分布如下:
用数组表示: − 1 -1 −1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 − 1 -1 −1
棋了分布说明:
- − 1 -1 −1代表白子, 0 0 0代表空位, 1 1 1代表黑子
- 数组长度 L L L,满足 1 < L < 40 1<L< 40 1<L<40, L L L为奇数
你得帮他写一个程序,算出最有利的出子位置。 最有利定义:
- 找到一个空位 ( 0 ) (0) (0),用棋子 ( 1 / − 1 ) (1/-1) (1/−1)填充该位置,可以使得当前子的最大连续长度变大
- 如果存在多个位置,返回最靠近中间的较小的那个坐标
- 如果不存在可行位置,直接返回 − 1 -1 −1
- 连续长度不能超过 5 5 5个(五字棋约束)
输入描述
第一行: 当前出子颜色。
第二行: 当前的棋局状态。
输出描述
1 1 1个整数,表示出子位置的数组下标
样例
输入
1
-1 0 1 1 1 0 1 -1 1
输出
5
说明
当前为黑子 ( 1 ) (1) (1),放置在下标为 5 5 5的位置,黑子的最大连续长度,可以由 3 3 3到 5 5 5
输入
-1
-1 0 1 1 1 0 1 0 1 -1 1
输出
1
说明
当前为白子,唯一可以放置的位置下标为 1 1 1,白字的最大长度,由 1 1 1变为 2 2 2
输入
1
0 0 0 0 1 0 0 0 0 1 0
输出
5
说明
可以的位置很多, 5 5 5最接近中间的位置坐标
思路:模拟
按照题意模拟即可。
有几个要求,
- 首先要使得落子后,当前子的最大连续长度变长
- 但是最大连续长度不能超过 5
- 如果存在多个落子位置都满足上述两个要求,则选择最靠近中间位置的一个,如果有多个位置都最靠近中间,则选择左边的
- 如果不存在这样的位置,返回-1
时间复杂度: O ( L 2 ) O(L^2) O(L2)
类似题目推荐
代码
C++
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 1;
cin >> x;
vector<int> vec;
int num;
// 因为长度未知,所以直到读不到数为止,这是一个数组,有若干个数
while (cin >> num) vec.push_back(num);
// 找到当前子在未落子前的最大连续长度 cur_max
int cur_max = 0;
for (int i = 0, j = 0; i < vec.size(); ++i) {
if (vec[i] == x) j += 1;
else j = 0;
cur_max = max(cur_max, j);
}
// len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
vector<int> len(vec.size());
// max_len 表示落子后,包含当前落子位置的最大连续长度
int max_len = 0;
for (int i = 0; i < vec.size(); ++i) {
if (vec[i] == 0) {
int L = i - 1, R = i + 1;
// 向左
while (L >= 0 && vec[L] == x) L -= 1;
// 向右
while (R < vec.size() && vec[R] == x) R += 1;
// 只有 <= 5 才合法
if (R - L - 1 <= 5) {
len[i] = R - L - 1;
max_len = max(max_len, R - L - 1);
}
}
}
// 如果 max_len 小于 cur_max,说明不存在答案
if (max_len <= cur_max || vec.empty()) {
cout << "-1\n";
return 0;
}
// 否则找距离中间位置最近的一个点,其落子后的连续长度最长
int ansidx = -1;
int mid = (vec.size() - 1) / 2;
for (int i = 0; i < vec.size(); ++i) {
if (len[i] > cur_max) {
if (ansidx == -1 || abs(ansidx - mid) > abs(i - mid)) {
ansidx = i;
}
}
}
cout << ansidx << "\n";
return 0;
}
python
x = int(input())
vec = list(map(int, input().split()))
# 找到当前子在未落子前的最大连续长度 cur_max
cur_max = 0
j = 0
for i in range(len(vec)):
if vec[i] == x:
j += 1
else:
j = 0
cur_max = max(cur_max, j)
# len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
len_vec = [0] * len(vec)
max_len = 0
for i in range(len(vec)):
if vec[i] == 0:
L, R = i - 1, i + 1
# 向左
while L >= 0 and vec[L] == x:
L -= 1
# 向右
while R < len(vec) and vec[R] == x:
R += 1
# 只有 <= 5 才合法
if R - L - 1 <= 5:
len_vec[i] = R - L - 1
max_len = max(max_len, R - L - 1)
# 如果 max_len 小于 cur_max,说明不存在答案
if max_len <= cur_max or len(vec) == 0:
print("-1")
else:
# 否则找距离中间位置最近的一个点,其落子后的连续长度最长
ansidx = -1
mid = (len(vec) - 1) // 2
for i in range(len(vec)):
if len_vec[i] > cur_max:
if ansidx == -1 or abs(ansidx - mid) > abs(i - mid):
ansidx = i
print(ansidx)
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int x = in.nextInt();
List<Integer> vec = new ArrayList<>();
while (in.hasNextInt()) {
int num = in.nextInt();
vec.add(num);
}
// 找到当前子在未落子前的最大连续长度 cur_max
int cur_max = 0;
int j = 0;
for (int i = 0; i < vec.size(); ++i) {
if (vec.get(i) == x) {
j += 1;
} else {
j = 0;
}
cur_max = Math.max(cur_max, j);
}
// len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
int[] len_arr = new int[vec.size()];
int max_len = 0;
for (int i = 0; i < vec.size(); ++i) {
if (vec.get(i) == 0) {
int L = i - 1, R = i + 1;
// 向左
while (L >= 0 && vec.get(L) == x) L -= 1;
// 向右
while (R < vec.size() && vec.get(R) == x) R += 1;
// 只有 <= 5 才合法
if (R - L - 1 <= 5) {
len_arr[i] = R - L - 1;
max_len = Math.max(max_len, R - L - 1);
}
}
}
// 如果 max_len 小于 cur_max,说明不存在答案
if (max_len <= cur_max || vec.size() == 0) {
System.out.println("-1");
} else {
// 否则找距离中间位置最近的一个点,其落子后的连续长度最长
int ansidx = -1;
int mid = (vec.size() - 1) / 2;
for (int i = 0; i < vec.size(); ++i) {
if (len_arr[i] > cur_max) {
if (ansidx == -1 || Math.abs(ansidx - mid) > Math.abs(i - mid)) {
ansidx = i;
}
}
}
System.out.println(ansidx);
}
}
}
Go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
scanner.Scan()
x, _ := strconv.Atoi(scanner.Text())
vec := make([]int, 0)
for scanner.Scan() {
num, _ := strconv.Atoi(scanner.Text())
vec = append(vec, num)
}
// 找到当前子在未落子前的最大连续长度 cur_max
cur_max := 0
j := 0
for i := 0; i < len(vec); i++ {
if vec[i] == x {
j += 1
} else {
j = 0
}
cur_max = max(cur_max, j)
}
// len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
lenArr := make([]int, len(vec))
maxLen := 0
for i := 0; i < len(vec); i++ {
if vec[i] == 0 {
L, R := i-1, i+1
// 向左
for L >= 0 && vec[L] == x {
L -= 1
}
// 向右
for R < len(vec) && vec[R] == x {
R += 1
}
// 只有 <= 5 才合法
if R-L-1 <= 5 {
lenArr[i] = R - L - 1
maxLen = max(maxLen, R-L-1)
}
}
}
// 如果 maxLen 小于 cur_max,说明不存在答案
if maxLen <= cur_max || len(vec) == 0 {
fmt.Println("-1")
} else {
// 否则找距离中间位置最近的一个点,其落子后的连续长度最长
ansIdx := -1
mid := (len(vec) - 1) / 2
for i := 0; i < len(vec); i++ {
if lenArr[i] > cur_max {
if ansIdx == -1 || abs(ansIdx-mid) > abs(i-mid) {
ansIdx = i
}
}
}
fmt.Println(ansIdx)
}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func abs(a int) int {
if a < 0 {
return -a
}
return a
}
Js
process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
input += data;
return;
});
process.stdin.on('end', () => {
const lines = input.trim().split('\n');
const x = parseInt(lines[0]);
const vec = lines[1].split(' ').map(Number);
// 找到当前子在未落子前的最大连续长度 cur_max
let cur_max = 0;
let j = 0;
for (let i = 0; i < vec.length; i++) {
if (vec[i] === x) {
j += 1;
} else {
j = 0;
}
cur_max = Math.max(cur_max, j);
}
// len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
let lenArr = new Array(vec.length).fill(0);
let maxLen = 0;
for (let i = 0; i < vec.length; i++) {
if (vec[i] === 0) {
let L = i - 1, R = i + 1;
// 向左
while (L >= 0 && vec[L] === x) {
L -= 1;
}
// 向右
while (R < vec.length && vec[R] === x) {
R += 1;
}
// 只有 <= 5 才合法
if (R - L - 1 <= 5) {
lenArr[i] = R - L - 1;
maxLen = Math.max(maxLen, R - L - 1);
}
}
}
// 如果 maxLen 小于 cur_max,说明不存在答案
if (maxLen <= cur_max || vec.length == 0) {
console.log("-1");
} else {
// 否则找距离中间位置最近的一个点,其落子后的连续长度最长
let ansIdx = -1;
let mid = Math.floor((vec.length - 1) / 2);
for (let i = 0; i < vec.length; i++) {
if (lenArr[i] > cur_max) {
if (ansIdx === -1 || Math.abs(ansIdx - mid) > Math.abs(i - mid)) {
ansIdx = i;
}
}
}
console.log(ansIdx);
}
});