【问题标题】:Unable to find what's wrong with my code for solve spoj CWC15无法找到解决 spoj CWC15 的代码有什么问题
【发布时间】:2015-05-06 16:58:15
【问题描述】:

我无法找到 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-制表 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 都在跟踪解决方案中包含的元素的数量,以便我可以判断分布在玩家数量方面是否相等。如果这些方法错误,则指向正确方向的提示是非常感谢。

【问题讨论】:

    标签: algorithm dynamic-programming memoization subset-sum


    【解决方案1】:

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

    解决它: 您不需要从1 to 200 00 000 获取所有总和,而只需在包含ith 播放器时迭代生成的总和。

    假设4 players 有经验2 3 4 5

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

    初始总和 0

    如果您包含第一个元素:0 和 2

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

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

    等等

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

    现在,如果您达到所需的总和,那么它是可以达到的。观察两支球队中相同数量的球员:我有一个提示,记得我提到“20000000 int 的地图”,我说 int 因为这张地图也可以用来存储多少数字可以达到特定的总和.使用按位运算符对此信息进行编码。您只需要维护计数而不是包含哪个特定元素。

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

    【讨论】:

    • 对于第一部分,更改导致从 tle 到 sigsev 的错误与制表错误相同,对于第一部分,我不认为有任何问题,请您详细说明您的想法错了。也看到这些 sigsev 错误让我相信我的方法不对。你能建议一个合适的方向吗?
    • 很抱歉,但对于第二部分和第一部分,您都写了“第一部分”,我不知道您指的是哪一部分。
    • 对此感到抱歉 :: 对于第一部分,更改导致错误从 tle 到 sigsev 与制表错误相同,对于第二部分,我认为没有任何问题,请您帮忙详细说明您认为错误的地方。还看到这些 sigsev 错误让我相信我的方法不对。您能建议一个合适的方向吗?
    • 对于第二部分,我也认为方法不正确。您正在遍历 sum 的所有值并添加 a[i],在这种方法中,您将多次计算 a[i] 以获得总和。此外 if(i==sum && dp[i-a[j-1]][j-1]) 行将为 4 {50 4 6 2} 之类的情况提供 segv,因为 50 将大于 sum (31)。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    相关资源
    最近更新 更多