Не удалось найти ошибку в моем коде для решения spoj CWC15.

Я не могу найти, что происходит не так как в мемотизации, так и в табулировании для spoj http://www.spoj.com/problems/CWC2015/.If вы могли бы указать, почему оба кода дают соответствующие ошибки, это было бы действительно полезно.

1 — Ошибка мемотизации — превышен лимит времени. Не знаю, почему сгенерированные случайные случаи и протестированные на ideone большинство решений выходят менее чем за секунду.

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<cstring>
using namespace std;
#define max 20000000

int a[40];
int n;
int m;
long long sum1;
bool dp[40][max];

int solve(long long sum,int x,int k)
{
    if(sum==0)
    {
        if(k==m)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else if(x==n)
    {
        return false;
    }
    else if(dp[x][sum])
    {
        return dp[x][sum];
    }
    else
    {
        return dp[x][sum]=(solve(sum,x+1,k)||solve(sum-a[x],x+1,k+1));
    }
}


int main()
{
    int t;
    scanf("%d",&t);
    for(int l=1;l<=t;l++)
    {
        scanf("%d",&n);
        m=n/2;
        long long sum=0;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        printf("Case %d: ",l);
        if(n%2)
        {
            printf("No\n");
            continue;
        }
        if(sum%2)
        {
            printf("No\n");
            continue;
        }
        sum=sum/2;
        if(solve(sum,0,0))
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}

2-tabulation Error-Sigsegv (ошибка сегментации) Я знаю, что ошибка сегментации может быть вызвана слишком большим размером массива. Но код отлично работает на ideone.

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
#include<cstring>
using namespace std;
#define max 20000000

int a[40];
int n;
long long sum;
bool dp[max+1][41];


bool solve()
{
    int k=0;
    //cout<<"sum is  "<<sum<<endl;
    for (int i = 0; i <= n; i++)
      dp[0][i] = true;
    for (long long i = 1; i <= sum; i++)
      dp[i][0] = false;

     for (long long i = 1; i <= sum; i++)
     {
       for (int j = 1; j <= n; j++)
       {
         dp[i][j] = dp[i][j-1];
         if (i >= a[j-1])
           dp[i][j] = dp[i][j] || dp[i - a[j-1]][j-1];
         if(i==sum && dp[i-a[j-1]][j-1])
         {
           k+=1;
         }
       }
     }

     /*cout<<k<<endl;*/

     return (dp[sum][n] && k==n/2);
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int l=1;l<=t;l++)
    {
        scanf("%d",&n);
        sum=0;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        printf("Case %d: ",l);
        if(n%2)
        {
            printf("No\n");
            continue;
        }
        if(sum%2)
        {
            printf("No\n");
            continue;
        }
        sum=sum/2;
        if(solve())
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}

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


person user3894045    schedule 06.05.2015    source источник


Ответы (1)


Предложение: способ, которым вы решаете, не будет работать из-за сложности. Хотя сложность пространства будет работать (ограничение 1536MB и используемое пространство около 785MB), но сложность времени слишком высока для ограничения времени 5s. Оценка 10 ^ 8 может быть безопасно выполнена в течение 1 секунды. Если вы отправляете только инициализирующую часть своего кода, это превысит ограничение по времени (я сделал это для проверки).

Чтобы решить эту проблему: вам не нужно путешествовать по всей сумме от 1 to 200 00 000, а просто повторять сгенерированную сумму при включении ith игрока.

Допустим, есть 4 players с опытом 2 3 4 5.

Вам не нужно путешествовать на сумму: 1 to 8, достаточно сделать что-то вроде этого:

Начальная сумма 0

если вы включаете 1-й элемент: 0 и 2

если вы включаете 2-й элемент: 0, 2, 3, 4

если вы включаете 3-й элемент: 0, 2, 3, 4, 6, 7

и т. д.

Таким образом, это может достигать 2 ^ N. Так что поддерживайте карту int 20000000 и не ставьте номер в очередь, если он там уже есть. Это решит вашу проблему итерации 20000000 * 40 для повторения только уникальных достижимых значений суммы (сложность будет зависеть от характера ввода).

Теперь, если вы достигли желаемой суммы, то она достижима. Чтобы следить за равным количеством игроков в обеих командах: у меня есть подсказка для вас, помните, я упоминаю «карту int of 20000000», я сказал int, потому что эта карта может также использоваться для хранения того, сколько чисел может достигать определенной суммы . Используйте побитовый оператор для кодирования этой информации. Вам просто нужно вести счет, а не какой конкретный элемент включен.

PS: Я решил эту проблему, это заняло некоторое время, и это было весело.

person pirate    schedule 12.05.2015
comment
В первой части изменение приводит к ошибке от файла к сигсеву так же, как и к ошибке табуляции. В первой части нет, я не думаю, что есть какие-то проблемы, не могли бы вы уточнить, что вы считаете неправильным. Также видеть эти ошибки сигсева заставляя меня поверить, что мой подход неверен. Не могли бы вы предложить подходящее направление. - person user3894045; 13.05.2015
comment
прошу прощения, но как для второй, так и для первой части, вы написали для первой части, я не понял, на какую часть вы ссылаетесь. - person pirate; 13.05.2015
comment
Извините за это :: В первой части изменение привело к ошибке от файла к сигсеву, такой же, как ошибка табуляции. Во второй части нет, я не думаю, что есть какие-то проблемы, не могли бы вы уточнить, что вы считаете неправильным. Также наблюдение за этими ошибками sigsev заставляет меня поверить, что мой подход неверен. Не могли бы вы предложить подходящее направление. - person user3894045; 13.05.2015
comment
Для второй части я тоже считаю подход неправильным. Вы проходите по всем значениям суммы и добавляете [i], в этом подходе вы будете вычислять [i] более одного раза для суммы. Также строка if(i==sum && dp[i-a[j-1]][j-1]) даст segv для случая 4 {50 4 6 2}, поскольку 50 будет больше, чем сумма (31). - person pirate; 14.05.2015