Diaesh Antony Ответов: 4

Как найти количество путей в матрице, имеющей максимальную сумму от верхнего левого угла до нижнего правого угла с препятствиями " x " на ней


Я написал функцию, использующую запоминание, чтобы подсчитать максимальное количество путей, имеющих максимальную сумму от верхнего левого до нижнего правого края матрицы.Мой код отлично работает для всех тестовых случаев, за исключением приведенного ниже случая, который показывает неверный вывод.Может ли кто-нибудь сказать мне, какая логика отсутствует в моем коде?

n-->15(size of matrix)
max_path_sum -->143(maximum sum from top left to bottom right)

e 1 1 7 x 7 6 8 4 2 2 7 3 4 8
5 2 3 x 2 5 2 3 8 x 8 2 x 8 1
6 3 1 x 2 9 9 4 7 x 9 8 1 8 6
8 1 x x 9 x 8 6 3 5 2 x 4 9 4
5 5 3 5 5 9 x 3 8 9 3 1 1 x 5
3 6 1 1 x x 2 3 x 3 7 9 4 9 2
6 9 1 8 x x 5 3 2 1 2 9 x 7 x
4 1 x 1 8 1 2 9 6 5 6 1 1 x 2
x 6 4 3 9 2 5 x 7 x 2 8 6 x x
8 6 x x 7 1 3 8 x 5 3 x x 6 7
4 5 6 5 6 1 9 x 3 4 2 2 2 2 8
x 7 5 2 2 8 x x 4 5 3 5 8 x 1
9 5 9 5 x 4 8 3 x x 5 6 1 2 6
1 4 x x x x 4 3 2 1 5 8 2 x 4
6 5 2 7 4 6 4 7 3 x 4 8 x 7 s


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char a[100][100];
int i,j,n,max_path_sum,max_path_count;

int isvalidate(int i, int j,int c)
{
    if(i >= 0 && i < n && j>=0 && j<n &&="" c="">=0 && c <= max_path_sum)
        return 1;
    else 
        return 0;
    
}
  
int max(int a,int b, int c)
{
     if(a >= b && a >= c)
         return a;
     else if(b >= a && b >= c)
         return b;
     else 
         return c;
}
/* Memoization approach to find the number of paths having the maximum sum */

int maxcountPath(int i,int j,int c)
{   
    int countDP[n][n][max_path_sum];
    
	if(i==0 && j==0 && c== 0)
	{   
		if(((a[i][j]-'0') - c) ==0)
			return countDP[i][j][c] = 1;
		else
			return countDP[i][j][c] = 0;
	}
	
	if(i==0 && isvalidate(i,j,c) && a[i][j] != 'x')
		return countDP[i][j][c] = maxcountPath(i,j-1,c-(a[i][j]-'0'));
	  
	else if(j==0 && isvalidate(i,j,c) && a[i][j] != 'x')
		return countDP[i][j][c] = maxcountPath(i-1,j,c-(a[i][j]-'0'));
    
    else if(isvalidate(i,j,c))
	    return countDP[i][j][c] = maxcountPath(i,j-1,c-(a[i][j]-'0')) + 
		  maxcountPath(i-1,j,c-(a[i][j]-'0')) + maxcountPath(i-1,j-1,c-(a[i][j]-'0'));
	else
	    return countDP[i][j][c] = 0;

}
/* DP approach to find the maximum sum path from top left corner to bottom right corner */

int maxsumPath(char a[][100], int n)
{   
    int maxpathDP[n][n];
    
    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
        {
            maxpathDP[i][j] = 0;
        }
    }
    
    for(i = 1; i < n; i++)
    {
        if(a[i][0] != 'x')
            maxpathDP[i][0] = a[i][0]-'0' +maxpathDP[i-1][0];
        else
            break;
    
    }
    
    for(j = 1; j < n; j++)
    {
        if(a[0][j] != 'x')
            maxpathDP[0][j] = a[0][j]-'0'+maxpathDP[0][j-1];
        else
            break;
    }
    
    for(i = 1; i < n; i++)
    {
        for(j = 1; j < n; j++)
        {
            if(a[i][j] == 'x')
            {    
                continue;
            }
            else
            {
                if(a[i][j] == 's')
                {   
                    maxpathDP[i][j] = max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]); 
                }
                else
                {
                 
                    maxpathDP[i][j] = a[i][j]-'0' + max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
                }
            }
        }
    }
    
   return maxpathDP[n-1][n-1];
    
}
 
int main()
{   
    int t;
    scanf("%d", &t);

    while(t--)
    {   
        scanf("%d", &n);
      
        for (i = 0; i < n; i++)
        {
            for (j = 0; j < n; j++)
            {
                scanf(" %c", &a[i][j]);
            }
        }
        
        max_path_sum = maxsumPath(a,n);
        
        a[0][0] = '0';
        a[n-1][n-1] = '0';
        
        max_path_count = maxcountPath(n-1,n-1,max_path_sum);
        
        if(max_path_count == 0)
		{
            max_path_sum = 0;
        }
        printf("%d %d\n",max_path_sum,max_path_count);
    }
    
    return 0;
}


Что я уже пробовал:

Изначально я столкнулся с SIGSEGV который фиксируется проверкой граничных условий

Patrice T

Какой результат вы получаете и какого результата ожидаете ?

Diaesh Antony

----ВХОД-----
5
15
e 1 1 7 x 7 6 8 4 2 2 7 3 4 8
5 2 3 x 2 5 2 3 8 x 8 2 x 8 1
6 3 1 x 2 9 9 4 7 x 9 8 1 8 6
8 1 x x 9 x 8 6 3 5 2 x 4 9 4
5 5 3 5 5 9 x 3 8 9 3 1 1 x 5
3 6 1 1 x x 2 3 x 3 7 9 4 9 2
6 9 1 8 x x 5 3 2 1 2 9 x 7 x
4 1 x 1 8 1 2 9 6 5 6 1 1 х 2
x 6 4 3 9 2 5 x 7 x 2 8 6 x x
8 6 x x 7 1 3 8 x 5 3 x x 6 7
4 5 6 5 6 1 9 x 3 4 2 2 2 2 8
x 7 5 2 2 8 x x 4 5 3 5 8 x 1
9 5 9 5 x 4 8 3 x x 5 6 1 2 6
1 4 x x x x 4 3 2 1 5 8 2 x 4
6 5 2 7 4 6 4 7 3 x 4 8 x 7 s
9
e 4 x 9 1 7 5 9 1
2 9 8 2 9 6 x 8 8
9 5 9 5 7 1 x 2 1
2 3 8 9 x 3 8 7 8
8 8 9 2 x 2 7 8 2
4 6 2 6 8 7 9 5 9
x 6 3 8 8 3 5 8 7
9 5 7 3 5 8 4 8 1
x 4 4 5 8 7 4 1 с
7
е 2 8 7 6 7 4
2 6 6 2 x 6 7
3 1 1 4 x 7 2
1 4 2 6 1 7 6
x 7 8 9 x 4 x
7 1 1 4 x 2 4
8 6 5 9 1 1 с
7
е 5 4 9 9 3 7
x 3 1 4 5 7 5
3 6 3 x 6 x 5
7 1 5 8 x 9 1
8 4 3 9 6 8 3
2 x x 5 9 3 7
3 2 6 4 7 4 с
3
е 6 1
4 8 9
9 9 с
----------ВЫХОД-------------------
143 ?
101 15
60 1
65 3
23 2

Patrice T

Совет: покажите достаточно кода, чтобы мы могли его запустить.

Diaesh Antony

#включить <stdio.h>
#include <string.h>
#include <stdlib.h>

char a[100][100];
инт я,J,Н,max_path_sum,max_path_count;

isvalidate типа int(тип int я, инт Дж,тип int в C)
{
если(я и gt;= 0 &&усилителя; я &Л; П &амп;&амп; Дж&ГТ;=0 &амп;&амп; Дж&ЛТ;п &ампер;&ампер;="" с=""&ГТ;=0 &&усилителя; г &ЛТ;= max_path_sum)
возврат 1;
еще
возвращает 0;

}

инт максимум(в инт,инт б, инт с)
{
Если(а &ГТ;= б &амп;&амп; в &ГТ;= с)
вернуть;
остальное, если(B &ГТ;= &ампер;&ампер; б &ГТ;= с)
вернуться б;
еще
возвращение с;
}
/* Подход к запоминанию для нахождения количества путей, имеющих максимальную сумму */

maxcountPath типа int(тип int я,инт Дж,тип int в C)
{
int countDP[n][n][max_path_sum];

если(i==0 & & amp; j==0 && c== 0)
{
если (((a[i][j]-'0') - c) ==0)
return countDP[i][j][c] = 1;
еще
return countDP[i][j][c] = 0;
}

если(я==0 &&усилителя; isvalidate(я,J,C) и усилитель;& а[я][Дж] != 'х')
вернуться countDP[я][Дж][с] = maxcountPath(я,J-1,С-(а[я][Дж]-'0'));

остальное, если(с j==0 &&усилителя; isvalidate(я,J,C) и усилитель;& а[я][Дж] != 'х')
вернуться countDP[я][Дж][с] = maxcountPath(я-1,J В,С-(а[я][Дж]-'0'));

остальное, если(isvalidate(я,J,к.))
вернуться countDP[я][Дж][с] = maxcountPath(я,J-1,С-(а[я][Дж]-'0')) +
maxcountPath(я-1,J В,С-(а[я][Дж]-'0')) + maxcountPath(я-1,j-1,и С-(а[я][Дж]-'0'));
еще
return countDP[i][j][c] = 0;

}
/* Подход DP для нахождения пути максимальной суммы от верхнего левого угла до нижнего правого угла */

int maxsumPath(char a[][100], int n)
{
int maxpathDP[n][n];

для(i = 0; i < n; i++)
{
для(j = 0; j < n; j++)
{
maxpathDP[i][j] = 0;
}
}

для(i = 1; i < n; i++)
{
если(a[i][0] != 'x')
maxpathDP[i][0] = a[i][0]-'0' +maxpathDP[i-1][0];
еще
перерыв;

}

для(j = 1; j < n; j++)
{
если(a[0][j] != 'x')
maxpathDP[0][Дж] = а[0][Дж]-'0'+maxpathDP[0][j-1 в];
еще
перерыв;
}

для(i = 1; i < n; i++)
{
для(j = 1; j < n; j++)
{
если(a[i][j] == 'x')
{
продолжить;
}
еще
{
если(a[i][j] == 's')
{
maxpathDP[i][j] = max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
}
еще
{

maxpathDP[i][j] = a[i][j]-'0' + max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
}
}
}
}

возврат maxpathDP[n-1][n-1];

}

тап_п()
{
int t;
scanf("%d", &t);

while(t--)
{
scanf("%d", &n);

для (i = 0; i < n; i++)
{
для (j = 0; j < n; j++)
{
scanf(" %c", &a[i][j]);
}
}

max_path_sum = maxsumPath(а,н);

а[0][0] = '0';
a[n-1][n-1] = '0';

max_path_count = maxcountPath(n-1,n-1,max_path_sum);

if(max_path_count == 0)
{
max_path_sum = 0;
}
printf("%d %d\n",max_path_sum,max_path_count);
}

возвращает 0;
}

CPallini

Пожалуйста, напишите точный код. Эта линия

if(i >= 0 && i < n && j>=0 && j<n &&="" c="">=0 && c <= max_path_sum)

даже не будет компилироваться.

4 Ответов

Рейтинг:
1

OriginalGriff

Если вы хотите, чтобы люди смотрели на ваш код, сделайте его легко читаемым. Это означает, что "ленивые имена переменных" - плохая идея, а имена одиночных символов-это именно то, что нужно.
Это означает, что вы не пишете код типа "if (...) return 1; else return 0;"
Это означает документирование вашего кода, чтобы люди имели некоторое представление о том, что вы намеревались сделать с кодом.
Это означает, что объяснение того, что вы ожидали от кода, и что именно он будет делать вместо этого: "это не сработало" - бесполезный отчет об ошибке, потому что он не говорит нам ничего, чего мы уже не знали: Если бы он работал, вы бы не задавали этот вопрос!
Это означает объяснение того, что вы пытались выяснить, в чем проблема.

И прежде всего, это означает понимание процесса развития ... Компиляция не означает, что ваш код верен! :смеяться:
Подумайте о процессе разработки как о написании электронного письма: успешная компиляция означает, что вы написали письмо на правильном языке - например, на английском, а не на немецком, - а не то, что письмо содержало сообщение, которое вы хотели отправить.

Итак, теперь вы входите во вторую стадию разработки (на самом деле это четвертая или пятая, но вы перейдете к более ранним стадиям позже): тестирование и отладка.

Начните с рассмотрения того, что он делает, и как это отличается от того, что вы хотели. Это важно, потому что это дает вам информацию о том, почему он это делает. Например, если программа предназначена для того, чтобы позволить пользователю ввести число, а затем удвоить его и напечатать ответ, то если бы вход / выход был таким:

Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16
Тогда совершенно очевидно, что проблема заключается в бите, который удваивает его - он не прибавляет себя к себе или умножает его на 2, он умножает его на себя и возвращает квадрат входного сигнала.
Таким образом, вы можете посмотреть на код, и очевидно, что он находится где-то здесь:
int Double(int value)
   {
   return value * value;
   }

Как только у вас появится идея, что может пойти не так, начните использовать отладчик, чтобы выяснить, почему. Поместите точку останова в первую строку метода и запустите приложение. Когда он достигнет точки останова, отладчик остановится и передаст управление вам. Теперь вы можете запускать свой код построчно (так называемый "одноступенчатый") и просматривать (или даже изменять) содержимое переменных по мере необходимости (черт возьми, вы даже можете изменить код и повторить попытку, если вам это нужно).
Подумайте о том, что должна делать каждая строка кода перед ее выполнением, и сравните это с тем, что она действительно делала, когда вы использовали кнопку "шаг вперед" для выполнения каждой строки по очереди. Он сделал то, что вы ожидали? Если да, то переходите к следующей строке.
Если нет, то почему? Чем это отличается?
Надеюсь, это поможет вам определить, в какой части этого кода есть проблема и в чем она заключается.
Это навык, и его стоит развивать, поскольку он помогает вам как в реальном мире, так и в развитии. И, как и все навыки, он только улучшается при использовании!


Рейтинг:
1

Patrice T

Цитата:
Может ли кто-нибудь сказать мне, какая логика отсутствует в моем коде?

Я думаю, что ваша проблема заключается в том, что maxsumPath можно принять во внимание какой-то невозможный путь.
Вы должны напечатать maxpathDP чтобы увидеть, как вы получаете максимальный путь.

Ваш код ведет себя не так, как вы ожидаете, или вы не понимаете, почему !

Существует почти универсальное решение: запускайте свой код на отладчике шаг за шагом, проверяйте переменные.
Отладчик здесь, чтобы показать вам, что делает ваш код, и ваша задача-сравнить с тем, что он должен делать.
В отладчике нет никакой магии, он не знает, что должен делать ваш код, он не находит ошибок, он просто помогает вам, показывая, что происходит. Когда код не делает того, что ожидается, вы близки к ошибке.
Чтобы увидеть, что делает ваш код: просто установите точку останова и посмотрите, как работает ваш код, отладчик позволит вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения.

Отладчик - Википедия, свободная энциклопедия[^]

Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]
Базовая отладка с помощью Visual Studio 2010 - YouTube[^]

1.11 — отладка программы (пошаговое выполнение и останова) | выучить C++[^]

Отладчик здесь только для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.


Рейтинг:
0

Stefan_Lang

Просто некоторые вещи, чтобы упростить ваш код и, возможно, сделать его более ясным, что происходит, и, что более важно, не происходит:

1. Все операторы return в вашей функции maxcountpath(...) присваивают значение локальному массиву countDP, а затем возвращают это значение. Поскольку countDP больше не будет использоваться после возврата, назначение бессмысленно. Поэтому вы должны просто вернуть назначенное значение вместо этого!

2. Как только вы удалите задания, вы поймете, что никогда не используете countDP Вы можете полностью исключить этот массив.

3. Если это условие:

if(i==0 && j==0 && c== 0)
это правда, это означает, что вы можете использовать 0 вместо i и j в следующей ветви. Это упрощает следующее, если таким образом, что вы поймете, что это всегда верно.

4. Вы проверяете две вещи одновременно: достигли ли вы начальной точки (0,0) и нашли ли вы путь с правильной суммой (c==0). Это затрудняет понимание того, что происходит при различных комбинациях этих двух условий. Вы должны разделить их на отдельные чеки.

5. Вы неоднократно проверяете, является ли ваша текущая ячейка "x". Вместо этого вы могли бы просто проверить один раз и вернуться - вы не можете пройти путь, используя эту ячейку!

6. Вы многократно преобразуете числовое значение ячейки a[i][j], что делает ваш код немного сложнее для чтения. Просто преобразуйте это значение один раз и сохраните его в локальной переменной.

7. Это хорошая идея, чтобы проверить ваш вклад, но зачем делать это несколько раз в каждую ветвь? Сделайте это прямо в начале функции, один раз! Тогда вам не нужно проверять позже.

Эти вещи упрощают вашу функцию до:
int maxcountPath(int i,int j,int c)
{
	// have we gone outside the bounds?
	if (!isvalidate(i,j,c))
		return 0;
	// after this point, you know your input is fine!

	// has the recursion reached the starting point?
	if(i==0 && j==0) // first part of your orginial check
	{   
		if (c==0) // second part
			return 1;
		else // this is new! If c!=0, your path is not correct!
			return 0;
	}
	// after this point, you know you're not at the starting point yet

	// do we have a valid cell?
	if (a[i][j] == 'x')
		return 0; // you shall not pass!
	// from this point we know we have a valid cell

	// convert and store current cell value:
	int cell_value = a[i][j]-'0';

	if(i==0) // are we in first row?
		return maxcountPath(i,j-1,c-cell_value);
	  
	else if(j==0) // are we in first column?
		return maxcountPath(i-1,j,c-cell_value));
    
	return maxcountPath(i,j-1,c-cell_value) + 
		maxcountPath(i-1,j,c-cell_value) + maxcountPath(i-1,j-1,c-cell_value);

}

С другой стороны, эти упрощения (в основном ранние возвраты), вероятно, избегают проблемы i или j, идущих ниже 0, поэтому вы можете упростить свой isvalidate() функция просто проверяет c. (и поскольку c может выйти за пределы границ только в том случае, если вы передадите неправильное значение из main (), вы, вероятно, можете полностью удалить эту функцию isvalidate() )


Diaesh Antony

Спасибо за предложение.
Рекурсивный подход будет хорошо работать для небольших входных данных, но он займет экспоненциальное время, если у нас есть очень большой входной сигнал.Как я могу изменить этот рекурсивный подход на DP

Stefan_Lang

Сначала я тоже думал избежать рекурсии, но потом понял, что для ввода размера NxN максимальная глубина рекурсии составляет всего 2*N - это не так уж плохо для N<1000, хотя вам, возможно, придется увеличить размер стека программы.

Если вы хотите избежать рекурсии, я бы лучше опубликовал отдельное решение с объяснениями для этого, для лучшей читабельности.

Diaesh Antony

Спасибо за ответ.
Пожалуйста, объясните эквивалентный подход динамического программирования для одной и той же рекурсивной функции.Я попытался реализовать его с помощью DP,но получил неверный вывод.


Rick York

Еще одно предложение : сохраните значения в двоичной форме, а не в ASCII. Таким образом, вам не придется так часто преобразовывать их в двоичное значение. Вы можете конвертировать их один раз и хранить их таким образом. Поскольку x-это особое значение, вы можете сохранить его также в двоичной форме, которая равна 120, и это, вероятно, должно получить постоянное определение. Это означает, что ваши значения будут варьироваться от 0 до 9, а затем значение X, 120 - все в двоичном формате.

Diaesh Antony

Я улучшил рекурсию для запоминания.Как я могу преобразовать maxcountPath() в динамическое программирование?

#включить <stdio.h>
#include <string.h>
#include <stdlib.h>

char a[100][100];
инт я,J,Н,max_path_sum,max_path_count;

isvalidate типа int(тип int я, инт Дж,тип int в C)
{
если(я и gt;= 0 &&усилителя; я &Л; П &амп;&амп; Дж&ГТ;=0 &амп;&амп; Дж&ЛТ;п &ампер;&ампер;="" с=""&ГТ;=0 &&усилителя; г &ЛТ;= max_path_sum)
возврат 1;
еще
возвращает 0;

}

инт максимум(в инт,инт б, инт с)
{
Если(а &ГТ;= б &амп;&амп; в &ГТ;= с)
вернуть;
остальное, если(B &ГТ;= &ампер;&ампер; б &ГТ;= с)
вернуться б;
еще
возвращение с;
}

maxcountPath типа int(тип int я,инт Дж,тип int в C)
{
int countDP[n][n];
int cell_value = a[i][j]-'0';

if (!isvalidate(i,j,c))
return countDP[i][j] = 0;

если(i==0 && j==0)
{
если (c==0)
return countDP[i][j] = 1;
еще
return countDP[i][j] = 0;
}


если (a[i][j] == 'x')
return countDP[i][j] = 0;

если(i==0)
return countDP[i][j] = maxcountPath(i,j-1,c-cell_value);

иначе если(j==0)
return countDP[i][j] = maxcountPath(i-1,j,c-cell_value);

return countDP[i][j] = maxcountPath(i,j-1,c-cell_value) +
maxcountPath(i-1,j,c-cell_value) + maxcountPath(i-1,j-1,c-cell_value);

}

int maxsumPath(char a[][100], int n)
{
int maxpathDP[n][n];

для(i = 0; i < n; i++)
{
для(j = 0; j < n; j++)
{
maxpathDP[i][j] = 0;
}
}

для(i = 1; i < n; i++)
{
если(a[i][0] != 'x')
maxpathDP[i][0] = a[i][0]-'0' +maxpathDP[i-1][0];
еще
перерыв;

}

для(j = 1; j < n; j++)
{
если(a[0][j] != 'x')
maxpathDP[0][Дж] = а[0][Дж]-'0'+maxpathDP[0][j-1 в];
еще
перерыв;
}

для(i = 1; i < n; i++)
{
для(j = 1; j < n; j++)
{
если(a[i][j] == 'x')
{
продолжить;
}
еще
{
если(a[i][j] == 's')
{
maxpathDP[i][j] = max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
}
еще
{

maxpathDP[i][j] = a[i][j]-'0' + max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
}
}
}
}

возврат maxpathDP[n-1][n-1];

}

тап_п()
{
int t;
scanf("%d", &t);

while(t--)
{
scanf("%d", &n);

для (i = 0; i < n; i++)
{
для (j = 0; j < n; j++)
{
scanf(" %c", &a[i][j]);
}
}

max_path_sum = maxsumPath(а,н);

а[0][0] = '0';
a[n-1][n-1] = '0';

max_path_count = maxcountPath(n-1,n-1,max_path_sum);

if(max_path_count == 0)
{
max_path_sum = 0;
}
printf("%d %d\n",max_path_sum,max_path_count);
}

возвращает 0;
}

Diaesh Antony

Я написал в динамическом программировании для функции maxcountPath()-функцию для нахождения количества путей, имеющих максимальную сумму.Но я получаю неверный вывод.Пожалуйста, помогите мне разобраться в логической ошибке

Это код, который я написал с DP для
#включить <stdio.h>
#include <string.h>
#include <stdlib.h>

char a[100][100];
инт я,J,Н,max_path_sum,Валь,max_path_count;

isvalidate типа int(тип int я, инт Дж,тип int в C)
{
если(я и gt;= 0 &&усилителя; я &Л; П &амп;&амп; Дж&ГТ;=0 &амп;&амп; Дж&ЛТ;п &ампер;&ампер;="" с=""&ГТ;=0 &&усилителя; г &ЛТ;= max_path_sum)
возврат 1;
еще
возвращает 0;

}

инт максимум(в инт,инт б, инт с)
{
Если(а &ГТ;= б &амп;&амп; в &ГТ;= с)
вернуть;
остальное, если(B &ГТ;= &ампер;&ампер; б &ГТ;= с)
вернуться б;
еще
возвращение с;
}

int maxcountPath(int n, int c)
{
int countDP[n][n];
memset(countDP, 0, sizeof(countDP));

countDP[0][0] = c;

для(i = 1; i < n; i++)
{
если(a[i][0] != 'x')
{
countDP[i][0] = countDP[i-1][0] - (a[i][0]-'0');
}
еще
перерыв;
}

для(i = 1 ; i < n; i++)
{
если(a[0][i] != 'x')
{
countDP[0][i] = countDP[0][i-1] - (a[0][i]-'0');
}
еще
перерыв;
}



для(i = 1; i < n; i++)
{
для(j = 1; j < n; j++)
{
если(a[i][j] != 'x')
{
val = a[i][j]-'0';
countDP[я][Дж] = (countDP[я-1][Дж]-вал)-(countDP[я][Дж-1]-вал)-(countDP[я-1][Дж-1]-вал);
}
еще
продолжить;
}

}

обратный отсчет: [n-1][n-1];

}

int maxsumPath(char a[][100], int n)
{
int maxpathDP[n][n];

для(i = 0; i < n; i++)
{
для(j = 0; j < n; j++)
{
maxpathDP[i][j] = 0;
}
}

для(i = 1; i < n; i++)
{
если(a[i][0] != 'x')
maxpathDP[i][0] = a[i][0]-'0' +maxpathDP[i-1][0];
еще
перерыв;

}

для(j = 1; j < n; j++)
{
если(a[0][j] != 'x')
maxpathDP[0][Дж] = а[0][Дж]-'0'+maxpathDP[0][j-1 в];
еще
перерыв;
}

для(i = 1; i < n; i++)
{
для(j = 1; j < n; j++)
{
если(a[i][j] == 'x')
{
продолжить;
}
еще
{
если(a[i][j] == 's')
{
maxpathDP[i][j] = max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
}
еще
{

maxpathDP[i][j] = a[i][j]-'0' + max(maxpathDP[i-1][j-1],maxpathDP[i-1][j],maxpathDP[i][j-1]);
}
}
}
}

возврат maxpathDP[n-1][n-1];

}

тап_п()
{
int t;
scanf("%d", &t);

while(t--)
{
scanf("%d", &n);

для (i = 0; i < n; i++)
{
для (j = 0; j < n; j++)
{
scanf(" %c", &a[i][j]);
}
}

max_path_sum = maxsumPath(а,н);

а[0][0] = '0';
a[n-1][n-1] = '0';

max_path_count = maxcountPath(n,max_path_sum);

if(max_path_count == 0)
{
max_path_sum = 0;
}
printf("%d %d\n",max_path_sum,max_path_count);
}

возвращает 0;
}

Stefan_Lang

Как вы могли заметить, размещение кода в комментарии - не самая лучшая идея! Если вы не примете особых мер предосторожности, форматирование будет потеряно и специальные символы в вашем коде будут преобразованы во что-то другое, что сделает код нечитаемым. Кроме того, размер шрифта здесь слишком мал, чтобы удобно читать большие разделы кода.

Если вы изменили свой исходный код, было бы проще, если бы вы просто указали, что вы изменили, и/или опубликовали только тот код, который вы изменили. Если вы сильно изменились, то, вероятно, лучше добавить его к исходному вопросу, используя зеленую ссылку [улучшить вопрос] в правом нижнем углу вопроса. Затем вы можете правильно отформатировать его, и другие также увидят и смогут прокомментировать его.

Что касается вашего вопроса, то ваше использование рекурсии-это динамическое программирование. Я не уверен, что вы хотите это знать.

Что касается вашего кода, то функция maxsumPath() корректно обрабатывает не все случаи. Важно не добавлять текущее значение к сумме, если соседняя ячейка, на которую вы смотрите, не имеет пути, ведущего к ней! Вы не смогли это проверить. Пример:
с 1 1 1
1 x x 1
1 x 9 1
1 1 1 е
В ячейке (2,2) вы вычислите максимальное значение 9, Даже если никакой путь не ведет от s к этой ячейке. Тогда ты получишь maxpathsum из 10, которые не могут быть получены с помощью любого допустимого пути!

Пожалуйста, обратите внимание, что я опубликовал нерекурсивный подход (решение 5). Не используя рекурсию, он решает проблему, решая сначала подзадачи, точно так же, как рекурсивный подход. Таким образом, он удовлетворяет требованиям для того, чтобы быть DP.

Рейтинг:
0

Stefan_Lang

В соответствии с запросом, вот как вам нужно создать нерекурсивное решение:

Вероятно, существует много различных подходов, но самый простой для объяснения в этом контексте-это просто перевернуть рекурсию вверх ногами:

Рекурсия работает, вычисляя результаты для задачи меньшего размера и выводя из этого решение для задачи полного размера. Итеративное решение возвращает этот подход, решая задачи наименьшего размера, и итеративно выводит решения для следующих задач большего размера. Очевидно, что вам нужно каким-то образом сохранить промежуточные результаты, и вам нужно убедиться, что вы получаете все меньшие решения, которые вам нужны на следующем шаге.

Для этой задачи частичными задачами, решаемыми итеративно, являются максимальное значение и количество максимальных путей от одной из конечных точек до одной позиции в Матрице NxN. Чтобы отслеживать эти два значения, я бы предложил создать простую структуру. И чтобы отслеживать все частичные решения, я бы создал массив NxN из этих структур:

struct sum_paths {
    int sum;
    int num_paths;
};
struct path_results {
    int rows;
    int columns;
    sum_paths* results;// must be allocated dynamically (and released when done)

    // get index for array element
    int at (int row, int column)
    {
        return row*columns+column;
    }

    // set values at array position
    void set_at(int row, int column, int sum, int npaths)
    {
        results[at(row, column)].sum = sum;
        results[at(row, column)].num_paths = npaths;
    }

    // retrieve values at array position
    sum_paths get_at(int row, int column)
    {
        return results[at(row, column)];
    }
};
Я добавил несколько полезных функций для упрощения чтения и записи.

Вы начнете с одного угла - в духе вашей рекурсивной программы, которая укореняет свою рекурсию в нижнем правом углу, я бы предложил начать с нижнего правого угла. Максимальное значение для достижения этой позиции равно 0, поскольку этой ячейке не присвоено никакого значения, а количество путей равно 1, поэтому вы присваиваете (0,1) результирующему массиву в позиции (N-1,N-1) :
// allocate matrix for intermediate results
path_results results;
// to do: allocate results array

// set position at end of path
int row = N-1;
int column = N-1;

// initialize end of path (sum = 0 and num_paths = 1)
results.set_at(row, column, 0, 1);


Далее вы можете вывести правильные значения для нижней строки, перейдя справа налево. Вы должны быть осторожны, что вы должны установить только значение != 0 здесь, если на самом деле есть путь, ведущий к ячейке справа от вас, и текущая ячейка не заблокирована:
for (column = N-2; column >= 0; --column)
{
    int sum = 0;
    int npaths = 0;
    if (A[row][column] != 'x')
    {
        npaths = results.get_at(row, column+1).num_paths;
        if (npaths > 0)
            sum = A[row][column]-'0' + results.get_at(row, column+1).sum;
    }
    results.set_at(row, column, sum, npaths);
}

Далее вы продолжаете снизу вверх и справа налево, чтобы заполнить набор результатов. Вы должны быть осторожны при проверке и объединении результатов из ячеек справа от вас, снизу и снизу справа: сначала вам нужно выяснить, какой путь дает максимальную сумму, а затем вам нужно добавить пути из каждого направления, которые действительно дают этот результат. И, конечно, вам всегда нужно проверить, есть ли правильный путь в любом направлении, чтобы начать с него.

В конце концов ваш процесс достигнет ячейки [0][0], и вы сможете распечатать результат.

Я оставлю детали реализации в качестве упражнения для вас. Если вы не получите результат 4, я предлагаю вам использовать отладчик в последнем примере, чтобы выяснить, что происходит не так. (и да, тот факт, что я знаю результат, означает, что у меня есть рабочая программа - но вы действительно должны попробовать это самостоятельно)


С. П.:
Вот код, который я использовал для вывода не только конечного результата, но и всего массива промежуточных результатов. Я обнаружил, что это довольно полезно, чтобы найти некоторые тонкие ошибки, которые я ввел в ранних версиях моего кода. Возможно, Вам это тоже пригодится:
for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j)
        cout << results.get_at(i, j).sum << ' ';
    cout << endl;
}
cout << endl;
for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j)
        cout << results.get_at(i, j).num_paths << ' ';
    cout << endl;
}
cout << endl;
cout << "maximum sum: " << results.get_at(0,0).sum << endl;
cout << "number of paths: " << results.get_at(0,0).num_paths << endl;