“Hackerearth 警察与小偷问题”

huangapple go评论78阅读模式
英文:

Hackerearth policeman and theives problem

问题

Sure, here's the translated version of your problem statement and code:


我正在尝试解决Hackeearth网站上的“警察和小偷问题”。我已经成功降低了时间复杂度,但有三个测试用例失败了。解决方案中似乎存在一个错误,导致了小的不匹配。我已经努力寻找错误几周了。以下是问题陈述和我的代码,

警察和小偷问题陈述:

给定一个大小为的网格,具有以下规格:

  • 网格中的每个单元格都包含警察或小偷。
  • 警察只能在他们位于同一行时抓住小偷。
  • 每个警察只能抓住一个小偷。
  • 警察不能抓住距离他们超过 K 个单位的小偷。
    编写程序,找出在网格中可以抓住的最大小偷数量。

输入格式

  • 第一行:T(测试用例数量)

    对于每个测试用例,

    • 第一行包含两个用空格分隔的整数 N 和 K
    • 接下来的 N 行包含 N 个用空格分隔的字符(表示网格中的每个单元格)

输出格式

对于每个测试用例,打印出可以在网格中抓住的最大小偷数量。

我的代码:

import java.io.*;
import java.util.*;

public class TestClass {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wr = new PrintWriter(System.out);
        int T = Integer.parseInt(br.readLine().trim());
        for(int t_i=0; t_i<T; t_i++)
        {
            String[] line = br.readLine().split(" ");
            int N = Integer.parseInt(line[0]);
            int K = Integer.parseInt(line[1]);
            char[][] A = new char[N][N];
            for(int i_A=0; i_A<N; i_A++)
            {
                String[] arr_A = br.readLine().split(" ");
                for(int j_A=0; j_A<arr_A.length; j_A++)
                {
                    A[i_A][j_A] = arr_A[j_A].charAt(0);
                }
            }

            int out_ = solution(A, K);
            System.out.println(out_);
            System.out.println("");
        }

        wr.close();
        br.close();
    }
    static int solution(char[][] A, int K){
        int count = 0;
        for(int i=0;i<A.length;i++){
            for(int j=0;j<A[i].length;j++){
                if(A[i][j]=='P'){
                    boolean thiefCaptured = false;
                    int x;
                    if(j-K >0){
                        x = j-K;
                    }else {
                        x = 0;
                    }
                    for(;x<j;x++) {
                        if (A[i][x] == 'T') {
                            A[i][x] = 'X';
                            A[i][j] = 'X';
                            count++;
                            thiefCaptured = true;
                            break;
                        }
                    }
                    int y;
                    if(j+K < A[i].length){
                        y = j+K;
                    }else{
                        y = A[i].length - 1;
                    }
                    for(;(y>j) && (thiefCaptured == false);y--){
                        if(A[i][y]=='T'){
                            A[i][y] = 'X';
                            A[i][j] = 'X';
                            count++;
                            break;
                        }
                    }
                }
            }
        }
        return count;
    }
}

我的逻辑
如果将一个元素视为搜索的中心,我首先从最左边(距离中心 k 个单位)开始寻找小偷,并朝中心迭代。如果未找到小偷,那么我会从最右边(距离中心 k 个单位)开始寻找小偷,朝中心迭代。

未通过的测试用例输入:

1
18 2
P P T T T P T P P T T P P P T P P T
P P P P T P P T P P T P P P T P T P
P P P T T T T T P P T P T P T T P T 
P P P P P P T P P P T T T P T T T P
P P T P P T P P P T T P P T P P P T
P T P P P P P P P P P P T T P T P P
T P T T T P P P P T P T T T T P T P
T T P T P P P P P P P T T T P T P P
P T T T T P T T P T P P P P T T P T
P T P P T T P P P P P T T P T P P P
P T P T T P T P T P T P P P P P P T
P T P P T P T P T P T P T T T P P P
T T P T P P P P P P T T T P T P T P
P T T P P P P P T P T P T P T P P T
P T P T T P T P T P P P P T P T P P
T P P P T P T P P P P P T T P P P P
P P T P P P P P P P P T T T P P T P
T T T P T P T P T P P T P P T P P P

预期输出
113

实际输出
112

你能帮助我找出问题出在哪里吗?我实际上已经努力解决这个问题几周了,但没有进展。我知道对于同一个问题存在另一种解决方案。但问题是,我想找出我的逻辑中的问题或漏洞。请帮助我解决这个问题。

链接:[在hackerearth上的“

英文:

I am trying to solve the Policeman and Theives problem in Hackeearth website. I am able to reduce the time complexity but three test cases are failing. There seems to be a bug in the solution which causes a small mismatch. I am struggling to find the error for weeks. Below are the problem statement and my code,

Policeman and Thieves Problem statement:

You are given a grid of size that has the following specifications:

  • Each cell in the grid contains either a policeman or a thief.
  • A policeman can only catch a thief if both of them are in the same row.
  • Each policeman can only catch one thief.
  • A policeman cannot catch a thief who is more than K units away from the policeman.
    Write a program to find the maximum number of thieves that can be caught in the grid.

Input format

  • First line: T (number of test cases)

    For each test case,

    • First-line contains Two space-separated integers N and K
    • Next N lines contain N space-separated characters (denoting each cell in the grid)

Output format

For each test case, print the maximum number of thieves that can be caught in the grid.

My code:

import java.io.*;
import java.util.*;

public class TestClass {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wr = new PrintWriter(System.out);
        int T = Integer.parseInt(br.readLine().trim());
        for(int t_i=0; t_i<T; t_i++)
        {
            String[] line = br.readLine().split(" ");
            int N = Integer.parseInt(line[0]);
            int K = Integer.parseInt(line[1]);
            char[][] A = new char[N][N];
            for(int i_A=0; i_A<N; i_A++)
            {
                String[] arr_A = br.readLine().split(" ");
                for(int j_A=0; j_A<arr_A.length; j_A++)
                {
                    A[i_A][j_A] = arr_A[j_A].charAt(0);
                }
            }

            int out_ = solution(A, K);
            System.out.println(out_);
            System.out.println("");
        }

        wr.close();
        br.close();
    }
    static int solution(char[][] A, int K){
        int count = 0;
        for(int i=0;i<A.length;i++){
            for(int j=0;j<A[i].length;j++){
                if(A[i][j]=='P'){
                    boolean thiefCaptured = false;
                    int x;
                    if(j-K >0){
                        x = j-K;
                    }else {
                        x = 0;
                    }
                    for(;x<j;x++) {
                        if (A[i][x] == 'T') {
                            A[i][x] = 'X';
                            A[i][j] = 'X';
                            count++;
                            thiefCaptured = true;
                            break;
                        }
                    }
                    int y;
                    if(j+K < A[i].length){
                        y = j+K;
                    }else{
                        y = A[i].length - 1;
                    }
                    for(;(y>j) && (thiefCaptured == false);y--){
                        if(A[i][y]=='T'){
                            A[i][y] = 'X';
                            A[i][j] = 'X';
                            count++;
                            break;
                        }
                    }
                }
            }
        }
        return count;
    }
}

My Logic
If an element is considered as the center of our search, then I am first looking for the thieves from the farthest left(by k units) and iterating towards the center. If the thief is not found, then I am looking for the thief from the farthest right(by k units) towards the center.

Failing test case input:

1
18 2
P P T T T P T P P T T P P P T P P T
P P P P T P P T P P T P P P T P T P
P P P T T T T T P P T P T P T T P T 
P P P P P P T P P P T T T P T T T P
P P T P P T P P P T T P P T P P P T
P T P P P P P P P P P P T T P T P P
T P T T T P P P P T P T T T T P T P
T T P T P P P P P P P T T T P T P P
P T T T T P T T P T P P P P T T P T
P T P P T T P P P P P T T P T P P P
P T P T T P T P T P T P P P P P P T
P T P P T P T P T P T P T T T P P P
T T P T P P P P P P T T T P T P T P
P T T P P P P P T P T P T P T P P T
P T P T T P T P T P P P P T P T P P
T P P P T P T P P P P P T T P P P P
P P T P P P P P P P P T T T P P T P
T T T P T P T P T P P T P P T P P P

Expected Ouput
113

Actual Output
112

Can you guys help me to figure out where I am going wrong? I am actually trying to figure out the solution for weeks but not able to progress. I know there is a different solution out there for the same question. But the thing is I would like to figure out the issue or the hole in my logic. Please help me out.

Link: Policemen and thieves on hackerearth

答案1

得分: 1

你的程序问题出现在第 i 行的第 11 列(如果按自然数/基于 1 的计数方式算,这是第 12 行)。

P T P P T P T P T P T P T T T P P P

这一行中有 8 名小偷。他们都可以被捕获。在下一行中,+ 表示捕获了小偷的警察,而 - 表示没有捕获小偷的警察。

+ T - + T + T + T + T + T T T + + -

(第一个小偷可以被左边或右边的警察捕获,对计数没有影响。关于谁会捕获前两个小偷还有更多可能的变化。)

你的程序只“捕获”了 7 名小偷中的 8 名。在这一行之前,你的计数为 68,我认为是正确的。在这一行之后,你的计数是 75,但应该是 76。

在这一行中,前 5 名小偷被正确捕获。现在考虑索引为 11 的警察会做什么?左边的小偷已经被捕获。右边有三名小偷。你的第二个最内层循环从 y = j+K = 11 + 2 = 13 开始倒数,所以捕获了索引为 13 的小偷,而索引为 12 的小偷没有被捕获。下一个警察的索引是 15。当 K 为 2 时,他/她无法捕获索引为 12 的小偷,距离太远。

编辑:我对解决方案的想法。 既然你已经发布了你的解决方案,我认为我可以发布我的解决方案而不会泄露任何内容。我的想法是,对于每个小偷,从左到右搜索一个可以捕获该小偷的警察。我将从上次搜索结束的地方开始搜索。这确保每个警察只捕获一个小偷。

char[] row = { 'P', 'T', 'P', 'P', 'T', 'P', 'T', 'P', 'T',
        'P', 'T', 'P', 'T', 'T', 'T', 'P', 'P', 'P' };
int k = 2; // 问题中的大写 K

int count = 0;
// 从哪里开始搜索下一个能够捕获小偷的警察
int pix = 0;
for (int ix = 0; ix < row.length; ix++) {
    if (row[ix] == 'T') {
        if (pix < ix - k) {
            pix = ix - k;
        }
        int searchLimit = Math.min(row.length, ix + k + 1);
        while (pix < searchLimit && row[pix] != 'P') {
            pix++;
        }
        if (pix < searchLimit) { // 找到了
            count++;
            pix++;
        }
    }
}

System.out.println(count);

输出:

8

我没有使用任何辅助数据结构,也没有修改输入数组。我认为这个算法是高效的(我没有在 hackerearth 上尝试过)。

问题在警察和小偷之间是对称的,所以也可以反过来做,对于每个警察,搜索一个要捕获的小偷,效果是一样的。

如果 Math.min() 调用让你感到不寻常,你可以使用 ? : 三元操作符或者 if-else 结构代替。

附注 或许在 hackerearth 上更合适的是用 P 表示警察,用 H 表示黑客,然后问有多少黑客在警察未捕获的情况下逃脱了。只是开个玩笑。

英文:

Your bug manifests in the line of i 11 (the 12th line if you count naturally/1-based).

P T P P T P T P T P T P T T T P P P

There are 8 thieves in this row. They can all be caught. In the following line a + indicates a policeman or policewoman successful of catching a thief, whereas - means one who doesn’t catch any.

+ T - + T + T + T + T + T T T + + -

(The first thief can be caught by either the police officer on the left or the right, it makes no difference to the count. There are yet more possible variations on who catches the first two thieves.)

Your program “catches” only 7 of the 8 thieves. Before this row you have a count of 68, which I believe is correct. After the row your count is 75, it should be 76.

In the row the first 5 thieves are caught as they should. Now what does the police officer at index 11 do? The thief to the left has already been caught. To the right are three thieves. Your second innermost loop counts down from y = j+K = 11 + 2 = 13, so catches the thief at index 13, leaving the thief at index 12 uncaught. The next police officer is at index 15.When K is 2, s/he cannot catch the thief at index 12, the distance is too great.

Edit: my idea for a solution. Since you have posted your solution, I think I can post mine without spoiling anything. My idea is for each thief to search left to right for a police officer who can catch that thief. I will start the search where the previous search left off. This ensures that each police officer catches only one thief.

	char[] row = { &#39;P&#39;, &#39;T&#39;, &#39;P&#39;, &#39;P&#39;, &#39;T&#39;, &#39;P&#39;, &#39;T&#39;, &#39;P&#39;, &#39;T&#39;,
			&#39;P&#39;, &#39;T&#39;, &#39;P&#39;, &#39;T&#39;, &#39;T&#39;, &#39;T&#39;, &#39;P&#39;, &#39;P&#39;, &#39;P&#39; };
	int k = 2; // The uppercase K from the problem
	
	int count = 0;
	// Index from where to search for the next police officer to catch a thief
	int pix = 0;
	for (int ix = 0; ix &lt; row.length; ix++) {
		if (row[ix] == &#39;T&#39;) {
			if (pix &lt; ix - k) {
				pix = ix - k;
			}
			int searchLimit = Math.min(row.length, ix + k + 1);
			while (pix &lt; searchLimit &amp;&amp; row[pix] != &#39;P&#39;) {
				pix++;
			}
			if (pix &lt; searchLimit) { // Found
				count++;
				pix++;
			}
		}
	}
	
	System.out.println(count);

Output:

> 8

I am not using any auxiliary data structures, and I am not modifying the input array. I believe that this algorithm is efficient (I have not tried it on hackerearth).

The problem is symmetrical in police officers and thieves, so one may do it the other way around, for each police officer search for at thief to catch, it will work the same.

If the Math.min() call feels unusual, instead use either the ? : ternary operator or an if-else construct.

PS Maybe on hackerearth it would have been more appropriate to have P for police officer and H for hacker and ask how many hackers got away without being caught by police. Just joking.

答案2

得分: 0

我已经添加了一个逻辑来修复 @OleV.V 指出的错误。添加的逻辑是,如果两名小偷连续出现在警察面前,先抓住最近的那个。现在,以前失败的测试用例通过了,但之前通过的三个测试用例由于时间复杂度问题而超时。下面是经过 @OleV.V 指出错误后的代码。现在需要根据时间复杂度来修复它 “Hackerearth 警察与小偷问题”

import java.io.*;
import java.util.*;

public class TestClass {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wr = new PrintWriter(System.out);
        int T = Integer.parseInt(br.readLine().trim());
        for(int t_i=0; t_i<T; t_i++)
        {
            String[] line = br.readLine().split(" ");
            int N = Integer.parseInt(line[0]);
            int K = Integer.parseInt(line[1]);
            char[][] A = new char[N][N];
            for(int i_A=0; i_A<N; i_A++)
            {
                String[] arr_A = br.readLine().split(" ");
                for(int j_A=0; j_A<arr_A.length; j_A++)
                {
                    A[i_A][j_A] = arr_A[j_A].charAt(0);
                }
            }

            int out_ = solution(A, K);
            System.out.println(out_);
            System.out.println("");
        }

        wr.close();
        br.close();
    }
    static int solution(char[][] A, int K){
        int count = 0;
        for(int i=0;i<A.length;i++){
            for(int j=0;j<A[i].length;j++){
                if(A[i][j]=='P'){
                    ArrayList<Integer> leftarr = new ArrayList<>();
                    ArrayList<Integer> rightarr = new ArrayList<>();
                    int x;
                    if(j-K >0){
                        x = j-K;
                    }else {
                        x = 0;
                    }
                    for(;x<j;x++) {
                        if (A[i][x] == 'T') {
                            leftarr.add(x);
                        }
                    }
                    if(leftarr.size() != 0){
                        Collections.sort(leftarr);
                        A[i][leftarr.get(0)] = 'X';
                        A[i][j] = 'X';
                        count++;
                        continue;
                    }
                    int y;
                    if(j+K < A[i].length){
                        y = j+K;
                    }else{
                        y = A[i].length - 1;
                    }
                    for(;y>j;y--){
                        if (A[i][y]=='T'){
                            rightarr.add(y);
                        }
                    }
                    if(rightarr.size()!=0){
                        Collections.sort(rightarr);
                        A[i][rightarr.get(0)] = 'X';
                        A[i][j] = 'X';
                        count++;
                    }
                }
            }
        }
        return count;
    }
}
英文:

I have added a logic to fix the bug pointed by @OleV.V. The added logic is, if two thieves are present consecutively to the Police, catch the nearest one first Now the failed test cases are passing but three of the previously passed test cases are getting timed out to time complexity issue. Below is the code, after addressing the bug pointed by @OleV.V. Now have to fix it in terms of time complexity “Hackerearth 警察与小偷问题”

import java.io.*;
import java.util.*;
public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int T = Integer.parseInt(br.readLine().trim());
for(int t_i=0; t_i&lt;T; t_i++)
{
String[] line = br.readLine().split(&quot; &quot;);
int N = Integer.parseInt(line[0]);
int K = Integer.parseInt(line[1]);
char[][] A = new char[N][N];
for(int i_A=0; i_A&lt;N; i_A++)
{
String[] arr_A = br.readLine().split(&quot; &quot;);
for(int j_A=0; j_A&lt;arr_A.length; j_A++)
{
A[i_A][j_A] = arr_A[j_A].charAt(0);
}
}
int out_ = solution(A, K);
System.out.println(out_);
System.out.println(&quot;&quot;);
}
wr.close();
br.close();
}
static int solution(char[][] A, int K){
int count = 0;
for(int i=0;i&lt;A.length;i++){
for(int j=0;j&lt;A[i].length;j++){
if(A[i][j]==&#39;P&#39;){
ArrayList&lt;Integer&gt; leftarr = new ArrayList&lt;&gt;();
ArrayList&lt;Integer&gt; rightarr = new ArrayList&lt;&gt;();
int x;
if(j-K &gt;0){
x = j-K;
}else {
x = 0;
}
for(;x&lt;j;x++) {
if (A[i][x] == &#39;T&#39;) {
leftarr.add(x);
}
}
if(leftarr.size() != 0){
Collections.sort(leftarr);
A[i][leftarr.get(0)] = &#39;X&#39;;
A[i][j] = &#39;X&#39;;
count++;
continue;
}
int y;
if(j+K &lt; A[i].length){
y = j+K;
}else{
y = A[i].length - 1;
}
for(;y&gt;j;y--){
if (A[i][y]==&#39;T&#39;){
rightarr.add(y);
}
}
if(rightarr.size()!=0){
Collections.sort(rightarr);
A[i][rightarr.get(0)] = &#39;X&#39;;
A[i][j] = &#39;X&#39;;
count++;
}
}
}
}
return count;
}
}

答案3

得分: 0

我从GeekForGeeks网站上找到了一个解决方案,它使用了一个非常简单的逻辑,基于警察和小偷的索引。我暗自想着,原来这么简单吗?嗯,这就是世界的运作方式。不管怎样,这里是上述问题的最优解决方案:

import java.io.*;
import java.util.*;

public class TestClass {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter wr = new PrintWriter(System.out);
        int T = Integer.parseInt(br.readLine().trim());
        for(int t_i=0; t_i<T; t_i++)
        {
            String[] line = br.readLine().split(" ");
            int N = Integer.parseInt(line[0]);
            int K = Integer.parseInt(line[1]);
            char[][] A = new char[N][N];
            for(int i_A=0; i_A<N; i_A++)
            {
                String[] arr_A = br.readLine().split(" ");
                for(int j_A=0; j_A<arr_A.length; j_A++)
                {
                    A[i_A][j_A] = arr_A[j_A].charAt(0);
                }
            }

            int out_ = solution(A, K);
            System.out.println(out_);
            System.out.println("");
        }

        wr.close();
        br.close();
    }
    static int solution(char[][] arr, int K){
        int count = 0;
        for(int i=0;i<arr.length;i++){
                ArrayList<Integer> thi = new ArrayList<>();
                ArrayList<Integer> pol = new ArrayList<>();
                for (int s = 0; s < arr[i].length; s++) {
                    if (arr[i][s] == 'P')
                        pol.add(s);
                    else if (arr[i][s] == 'T')
                        thi.add(s);
                }
                int l = 0, r = 0;
                while (l < thi.size() && r < pol.size()) {
                    if (Math.abs(thi.get(l) - pol.get(r)) <= K) {
                        count++;
                        l++;
                        r++;
                    }
                    else if (thi.get(l) < pol.get(r))
                        l++;
                    else
                        r++;
                }
        }
        return count;
    }
}

链接:Geek for Geeks上的Policeman and Thieves问题

英文:

I got a solution from GeekForGeeks website, which uses a really simple logic, based on the index of police and thief. I thought to myself, it's that simple!!!?? Well, it's how the world works. Anyways here is the optimum solution for the above problem,

import java.io.*;
import java.util.*;
public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int T = Integer.parseInt(br.readLine().trim());
for(int t_i=0; t_i&lt;T; t_i++)
{
String[] line = br.readLine().split(&quot; &quot;);
int N = Integer.parseInt(line[0]);
int K = Integer.parseInt(line[1]);
char[][] A = new char[N][N];
for(int i_A=0; i_A&lt;N; i_A++)
{
String[] arr_A = br.readLine().split(&quot; &quot;);
for(int j_A=0; j_A&lt;arr_A.length; j_A++)
{
A[i_A][j_A] = arr_A[j_A].charAt(0);
}
}
int out_ = solution(A, K);
System.out.println(out_);
System.out.println(&quot;&quot;);
}
wr.close();
br.close();
}
static int solution(char[][] arr, int K){
int count = 0;
for(int i=0;i&lt;arr.length;i++){
ArrayList&lt;Integer&gt; thi = new ArrayList&lt;&gt;();
ArrayList&lt;Integer&gt; pol = new ArrayList&lt;&gt;();
for (int s = 0; s &lt; arr[i].length; s++) {
if (arr[i]
展开收缩
== &#39;P&#39;) pol.add(s); else if (arr[i]
展开收缩
== &#39;T&#39;) thi.add(s); } int l = 0, r = 0; while (l &lt; thi.size() &amp;&amp; r &lt; pol.size()) { if (Math.abs(thi.get(l) - pol.get(r)) &lt;= K) { count++; l++; r++; } else if (thi.get(l) &lt; pol.get(r)) l++; else r++; } } return count; } }

Link: Policeman and Thieves Geek for Geeks

huangapple
  • 本文由 发表于 2020年5月30日 15:58:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/62099494.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定