无法找到解决问题CWC15的代码有什么问题

时间:2015-05-06 16:58:15

标签: algorithm dynamic-programming memoization subset-sum

我无法在memj http://www.spoj.com/problems/CWC2015/.If的memotization和tabulation中找到出错的地方,你可以指出为什么两个代码都会给出相应的错误,这些错误会非常有用。

1 - Memotization 错误 - 超出时间限制。 不知道为什么生成随机案例并在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 - 制表 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都跟踪解决方案中包含的元素的数量,以便我可以判断分配在玩家数量方面是否相等。如果这些方法是错误的,那么向正确方向的提示将是非常感谢。

1 个答案:

答案 0 :(得分:1)

建议: 由于复杂性,您解决的方式不起作用。虽然空间复杂度可行(限制为1536MB且使用的空间约为785MB),但时间复杂度对于5s的时间限制来说太高了。可以在1秒内安全地执行估计10 ^ 8。如果您只提交代码的初始化部分,它将超过时间限制(我已经完成了验证)。

解决它: 你不需要从1 to 200 00 000旅行所有总和,而只需在包含ith玩家时迭代生成的总和。

让我们说4 players有经验2 3 4 5

你不需要旅行总和:1 to 8,而是做这样的事情:

初始总和0

如果你包含第一个元素:0&amp; 2

如果包含第二个元素:0,2,3,4

如果包含第3个元素:0,2,3,4,6,7

现在这样它可以达到2 ^ N.因此,维护一个20000000的int映射,如果已存在,则不要将数字放入队列中。这将解决您的迭代问题20000000 * 40,以迭代唯一可达的和值(复杂性将取决于输入的性质)。

现在,如果您达到预期的金额,则可以达到。要观察两队中相同数量的球员:我有一个暗示你,记得我提到&#34; 200的地图和#34;我说int因为这张地图也可以用来存储多少数字可以达到特定金额。使用按位运算符对此信息进行编码。您只需要维护计数,而不是包含哪个特定元素。

PS:我解决了这个问题,花了一段时间,很有趣。