Loading...
ArmenPotourlyan+deleted! avatar ArmenPotourlyan+deleted! 488 Точки

[Useful Info][Exercises] - Advanced C# - Stacks and Queues - Problem{11} - Poisonous Plants [Spoiler Alert]

Здравейте, колеги,

 

Как ви се струва C# Advanced в SoftUni 3.0 засега? Мен лично много ме кефи, най-вече понеже е пълно със задачки за уплътняване на времето. Задачите за речници и множества бяха доста приятни, тези за матрици – отвратителни, а пък за стекове и опашки... еми, безобидни (ха-ха). Някои ги решавах по 15 минути, а други по ... 15 часаsurprise. В обобщение:

Ах, тези отровни растения!!! angry

 

В крайна сметка след редица съвети от инструкторите и малко четене за The Stock Span Problem успях да излъжа Judge и да взема максималните точки за Poisonous Plants. Ще нахвърля идеята без да поствам кода.

Нека имаме следната колекция от растения (всяко число показва количеството пестициди):

{ 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8 }

 

Растенията, които съдържат повече пестициди от съседите им вляво, умират. Ето как се развива това във времето:

Day 0: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 1: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 2: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 3: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 4: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 5: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 6: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

Day 7: 6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8

 

Ако съпоставим на всяко едно растение i дните daySpan[i], които то живее:

{ ∞ ∞ 1 ∞ 1 1 2 ∞ 1 1 2 1 2 3 4 5 1 2 3 1 4 1 6 7 1 }

 

Оттук можем да измислим алгоритъм за решаване на задачата:

  • Ще обхождаме масива от растения отляво надясно.
  • Ще пазим растението с най-малко пестициди до момента (текущите минимални стойности показват растенията, които ще живеят вечно).
  • Ще пресмятаме колко дни живот има дадено растение и ще ги отбелязваме в допълнителен масив daySpan[i].
  • За да изпълним горната стъпка, ще пазим индексите на избрани предишни растения в стек.
  • Ще пазим максималното време на живот(максималния елемент в daySpan) до момента.

В стека на някои стъпки се вкарва по повече от един елемент и се изкарва по повече от един елемент, но въпреки това като цяло мисля, че можем да приемем, че алгоритъмът е със сложност O(n). След като обходим всички растения променливата, която пази максималното време на живот, съдържа отговора, след колко дни растенията ще престанат да умират.

 

[SPOILER ALERT] Стъпка по стъпка:

plant iteration min daySpan indexStack indexStack maxSpan
6 0 6 Infinity Empty  >> Empty 1
5 1 5 Infinity Empty  >> Empty 1
8 2 5 Empty  >> { 2 } 1
4 3 4 Infinity { 2 }  >> Empty 1
7 4 4 1 Empty  >> { 4 } 1
10 5 4 1 { 4 }  >> { 5 } 1
9 6 4 2 { 5 }  >> { 6 } 2
2 7 2 Infinity { 6 }  >> Empty 2
3 8 2 1 Empty  >> { 8 } 2
11 9 2 1 { 8 }  >> { 9 } 2
6 10 2 2 { 9 }  >> { 10 } 2
9 11 2 1 { 10 }  >> { 11, 10 } 2
8 12 2 2 { 11, 10 }  >> { 12 } 2
7 13 2 3 { 12 }  >> { 13 } 3
5 14 2 4 { 13 }  >> { 14 } 4
4 15 2 5 { 14 }  >> { 15 } 5
13 16 2 1 { 15 }  >> { 16, 15 } 5
10 17 2 2 { 16, 15 }  >> { 17, 15 } 5
8 18 2 3 { 17, 15 }  >> { 18, 15 } 5
9 19 2 1 { 18, 15 }  >> { 19, 18, 15 } 5
6 20 2 4 { 19, 18, 15 }  >> { 20, 15 } 5
15 21 2 1 { 20, 15 }  >> { 21, 20, 15 } 5
4 22 2 6 { 21, 20, 15}  >> { 22 } 6
3 23 2 7 { 22 }  >> { 23 } 7
8 24 2 1 { 23 }  >> { 24, 23 } 7

 

Мистериозното намиране на стойността daySpan[i]:

  • Ако plant[i] <= min, изчисти стека, сложи daySpan[i] = Infinity, continue;
  • Ако няма нищо в стека, вкарай текущия индекс, daySpan[i] = 1, continue;

Нека poppedIndex = indexStack.Pop().

  • Ако plant[i] > plant [poppedIndex], сложи daySpan[i] = 1;
  • Докато plant[i] <= plant [poppedIndex], daySpan[i] = daySpan[poppedIndex] + 1;

На всяка стъпка се вкарва текущия индекс в стека. Трябва обаче да се преценят случаите, когато трябва да върнем обратно в стека индекс (с Push), който вече сме изкарали (с Pop).

 

ПП. Прощавайте за дългия пост blushblush

Тагове:
28
C# Advanced 21/05/2016 18:16:42
kaloyannikov avatar kaloyannikov 531 Точки

Разбрах решението със стек но възможно ли е да се реши само с матрица http://pastebin.com/sCi3vNrH

докарва го донякъде тоя тест който даде излиза ,нулевия също , 5 4 3 2 1 и 1 2 3 4 5 също , но на някои тестове дава Runtime Error и последните 2 за време гърмят. 

0
22/05/2016 14:52:09
ArmenPotourlyan+deleted! avatar ArmenPotourlyan+deleted! 488 Точки

Runtime Error-ите са ти от j-цикъла. Броячът става -1 и се опитваш да достъпиш масив с отрицателен индекс. С поправката на цикъла излиза 44/100 - има някъде грешка в логиката.

 

Последните два теста с този алгоритъм не би трябвало да успееш да ги минеш. В най-лошия случай имаш минимален пръв член и после последователно намаляваща редица от n - 1 числа, всичките от които са по-големи от първия член. Това означава, че външният цикъл ще се извърти n - 1 пъти, а вътрешният ще се извърта i - 1 пъти. Пример:

{ 3 10 9 7 6 5 }

i = 1;    няма вътрешен цикъл
i = 2;    j = 1 до 1
i = 3;    j = 2 до 1
i = 4;    j = 3 до 1
i = 5;    j = 4 до 1

Ако бяха n-числа:

i = n - 1     j = n - 2 до 1

Или операциите във вътрешния цикъл ще се изпълнят (1 + 2 + ... + n - 2) =  (n - 2) (n - 1) / 2 пъти. Понеже се интересуваме единствено от най-високата степен на n, това означава, че алгоритъмът ти е O(n на степен 2). Или времето за изпълнение ще ти бъде пропорционално на квадрата количеството на входните данни.

 

За разлика от този алгоритъм в алгоритъма със стека би ти се наложило да изхвърлиш най-много n - елемента от стека при това при една-единствена стъпка, т. е. операциите във вътрешния цикъл ще имаш (1 + 1 + 1 + ... + 1) + n или 2 * n, което е O(n). Или времето на изпълнение ще бъде пропорционално количеството на входните данни. Не я смятам коректно в този пример сложността, коефициента пред n ще е по-голям, но няма значение, важното е, че алгоритъмът е линеен... 

 

 

3
kaloyannikov avatar kaloyannikov 531 Точки

Благодаря за разяснението :)

0
djc_bg2015 avatar djc_bg2015 923 Точки

Здравей,

повечето задачки са взети от хакер ранк.

Конкретно ако те интертесува повече относно тази, тук има цяла дискусия, с обсъждане на ралзични алгоритми за решаването и:

https://www.hackerrank.com/contests/countercode/challenges/poisonous-plants/forum

Поздрави!

4
msmilkoff avatar msmilkoff 338 Точки

Аз я реших с клас за растението, където му пазех количеството пестицид и максималното време на живот (или твоето daySpan) като по този начин един от тестовете гърми за памет. Решението на този проблем е следното - ако го направим със структура вместо с клас дава  100 точки, защото структурата е стойностен тип и се пази в стека, а не в хийпа, което я прави и по-бърза, но това е само ако я използваш по предназначение - т.е. максимум с 2-3 пропъртита.

2
AntyfrizZz avatar AntyfrizZz 238 Точки

Здравейте,

Аз я реших с динамично оптимиране. Не знам дали е по - добро решение, но даде 100/100 с памет на границата и време 0.031s -0.046s

  • Всичко става с цикъл, който обхожда всички растения.
  • Стойностите на дните държа в масив
  • На всяко растение се пуска цикъл от предходното му до началото.
  • Преди да се пусне 2рия цикъл се проверява, дали съответното растение е с по - малко пестициди от минималното до момента. Ако е, правим него минимално. Това го правя, за да пропусна излишно въртене на 2рия цикъл.
  • Преди завъртане на 2рия цикъл сетвам дните на растението на 1 (все пак е по - голямо от минималното и все някога ще си замине). 
  • Ако не е по - малко, то във втория цикъл имам 2 варианта
    • растението, от което съм пуснал цикъла да е по - голямо от растението на което е 2рия цикъл в момента - break;
    • else.
      • Във втория вариант имам един иф. Ако дните на растението от 2тория цикъл са >= от дните на текущото, сетвам дните на текущото да са равни на това растение + 1. След това проверявам дали максималните дни са надминати. Ако са надминати - break; - няма как да умре за повече дни от максималните до момента. Без този break; последните 2 теста не минават.

Не направих добро обяснение като Армен, но толкова от мен :Д.

Ако някой има нужда от повече разяснения по метода на решение, може да ми пише в скайп или съответно тук.

Ако имате идеи за подобрение ще се радвам да ги споделите.

Поздрави!

2
valenteeeen avatar valenteeeen 6 Точки

Здравейте!

Опитах да реша задачата и със стек, и без стек, но последните два теста "гърмят" за време и Judge - а ми дава само 77 точки за 11. Poisonous Plants.

Тук използвам стек и лист:

using System;
using System.Collections.Generic;
using System.Linq;

class _11_06_PoisonousPlants
{
    static void Main()
    {
        int n = int.Parse(Console.ReadLine()), k = 0, p = 0;
        List<int> numbers = Console.ReadLine().Split().Select(int.Parse).ToList();
        int length = numbers.Count;
        Stack<int> que = new Stack<int>();
        while(true)
        {
            for (int i = 0; i < length - 1; i++)
                if (numbers[i] < numbers[i + 1])que.Push(i + 1);
            p = que.Count();
            for (int i = 0; i < p; i++) 
                numbers.RemoveAt(que.Pop());
            if (length > numbers.Count)
                k++;
            else
            {
                Console.WriteLine(k); break;
            }
            length = numbers.Count;
        }
    }
}
 

0
29/05/2016 00:34:01
valenteeeen avatar valenteeeen 6 Точки

Без да използвам стек - но последните два теста "гърмят" за време и Judge - а ми дава само 77 точки за 11. Poisonous Plants.

Тук не използвам стек, а само  лист:

using System;
using System.Collections.Generic;
using System.Linq;

class _11_04_PoisonousPlants
{
    static void Main()
    {
        int n = int.Parse(Console.ReadLine()), k = 0;
        List<int> numbers = Console.ReadLine().Split().Select(int.Parse).ToList();
        int length = numbers.Count;
        while(true)
        {
            for (int i = length - 1; i > 0; i--)
            {
                if (numbers[i - 1] < numbers[i])
                {
                    numbers.RemoveAt(i);
                      if(i==1)break;
                }
            }
            if (length > numbers.Count)
                k++;
            else break;
            length = numbers.Count;
        }
        Console.WriteLine(k);
    }
}

/*
6
3 10 9 7 6 5        
5

7
6 5 8 4 7 10 9        
2

25
6 5 8 4 7 10 9 2 3 11 6 9 8 7 5 4 13 10 8 9 6 15 4 3 8
7
*/

0
29/05/2016 00:36:08
ArmenPotourlyan+deleted! avatar ArmenPotourlyan+deleted! 488 Точки

Колегата AntyfrizZz е дал идея за решение без стек. Аз лично не съм я решавал без стек. Изглежда, че ако се поставят достатъчно хитри условия, за да не се върти вътрешния цикъл излишно, може да се излъже Judge-a.

 

Като цяло обаче, и със стек, и без стек, идеята е външният цикъл да обикаля растенията и няма изваждане на елементи. Ако ще вадим елементи по-добре да ползваме опашки - там изваждането на елемент ще е за константно време, докато за лист е линейно. Дори с опашки обаче не успява да мине последните два теста. Просто не трябва да се вадят елементи и това е. 

0
Alex_29 avatar Alex_29 5 Точки

Стигнах до това решение http://pastebin.com/qYBRZLeA с което взимам 88т. Не мога да разбера къде е грешката и моля за малко помощ.

0
ArmenPotourlyan+deleted! avatar ArmenPotourlyan+deleted! 488 Точки

Определено има грешка в логиката. Нямам достатъчно време, за да разбера напълно идеята ти, но ти давам тест, на който се проваля програмата:

Day 0: 6 5 8 4 7 10 9 2 3 11 6

Day 1: 6 5 8 4 7 10 9 2 3 11 6

Day 2: 6 5 8 4 7 10 9 2 3 11 6

На изхода трябва да дава 2, при теб дава 3.

 

Може би, ако си го дебъгнеш с този тест, ще разбереш къде точно се дъни работата.

1
30/05/2016 22:40:58
Alex_29 avatar Alex_29 5 Точки

Благодаря, помогна ми много теста.Промених кода на http://pastebin.com/n9iLCgXX и станаха 100/100 точки.

1
LardaX avatar LardaX 15 Точки

Здравейте, искам да използвам темата и аз да задам въпрос. Кодът ми е на Java, но за конкретната задача мисля, че няма абсолютно никакво значение.
Както и на други колеги имам проблеми с времето за последните 2 теста. Логиката ми е малко по-различна, но изглежда не сработва. Има ли вариант да се оптимизира, така че да мине или трябва да пробвам да напиша някое от другите решения?
http://pastebin.com/E2cCkZ70

0
DimoUrumov avatar DimoUrumov 2 Точки

При мен излиза всичко с изключение на ограничението за време на последните 2. Всичко отговаря на условията.

https://pastebin.com/xKG2CQ3r

От начало мислех да използвам обекти за цветята, но смисъла е никакъв, след като и обикновен ArrayList със стойността на отровата (пестицида) върши работа.

1) Създавам масива с предварително дадения капацитет.

2) Вкарвам растенията (като числа).

3) Намирам кои позиции трябва да отпаднат.

4) Махам елементите в обратен ред (т.е. от последното към първото, за да не се променят номерата им)

5) Цикля докато има умрели растения.

6) Явно нещо не е наред. Трябва да се оптимизира.

0
20/05/2017 12:16:47
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.