问题链接:: http://www.hackerearth.com/the-big-bang-challenge/algorithm/subset-and-4/
问题在于您获得了一个Z
个数字和一些n
个整数。你必须找到是否有n个整数的子集AND(按位运算符)Z给出零,如果是,则打印“是”否则打印“否”。
我知道一个简单的方法就是对所有输入n个数字和Z进行检查,看看它是否给出零。但是当我第一次看到这个问题时,我无法意识到这一点。我其实觉得非常愚蠢。
这是我在阅读问题时首次编写的代码::
#include <stdio.h>
int main()
{
int t;
int n;
long int z;
int i,j,x;
long int a[1000];
int b[30];
int count,count2;
int flag;
scanf("%d",&t);
while(t--)
{
scanf("%ld %d",&z,&n);
count=0;
for(i=0;i<n;i++)
scanf("%ld",&a[i]);
for(i=0;i<30;i++)
b[i]=-1;
j=0;
for(i=0;i<25;i++)
{
if(z&1==1)
{
b[j++]=i;
count++;
}
z=z>>1;
}
flag=0;
count2=0;
for(i=0;i<n;i++)
{
for(j=0;j<count;j++)
{
x=a[i];
if(b[j]!=-1)
{
x=x>>b[j];
// printf("New x=%d\nx&1=%d\n",x,x&1);
x==x&1;
if(x==0)
{
count2++;
b[j]=-1;
}
// printf("Count2=%d and Count1=%d\n",count2,count);
}
}
if(count2>=count)
{
flag=1;
break;
}
}
if(flag==0)
printf("No\n");
else
printf("Yes\n");
}
return 0;
}
我的代码实际上打算做什么?
在我的代码中,我检查整数Z的二进制表示,并计算数字中出现的1的数量,并在单独的数组b[30]
中记录1的位置。然后我将所有n
整数存储在数组a[1000]
中并检查所有整数,如果它们中的任何一个在我0
中存储的位置都有b[30]
,如果有的话然后我将b [30]位置标记为标记,这样我就不会在a [1000]中的前面数字中再次检查该位位置。如果我为b [30]中存储的所有位置找到零,那么我打印是,否则我打印否。
我知道与我应该做的相比,这是一个非常令人困惑和糟糕的算法。 但是,请帮助伙计们。我提交时,我的代码给出了错误的答案。
例如:: Z = 5,那么Z的二进制将是1001
,即1
在第0位和第3位。因此,在数组b [30]中,我将位置存储在位为1的Z中。就像这里一样,我将0
存储在b[0]
(对于Z中的第一个有效位),然后存储{ {1}}在b [1](对于下一个有效位),我这样做20位(根据我的需要),如果任何位是1,那么我将它的位置存储在3
。
然后,我开始将我存储在[1000]中的所有元素一个接一个地存储在x中,然后从b[j++]
数组中获取1个位置,我先前处理过,右移x很多位置并检查最右边的位是否为1.例如,我的[1000]数组有2个元素,3和1. 3是0011,我将3存储在x中,取b [0]然后执行x&gt;&gt; ; b [0],在这种情况下是相同的0011(因为b [0]是0)。然后我通过执行b[30]
检查最右边的位,返回1,因此该位不为零,所以我向前移动到b [1],即3,然后我执行x&gt;&gt; b [1] ,给出x&1
,然后我检查x&amp; 1,它给我零。所以,现在我知道我在数组中有一个第3位为零的数字,所以我将b [1]标记为-1,这样我就不再检查[1000]中的下一个整数。然后我取0000
这是[1000]的第二个元素,然后执行与上面相同的步骤,我发现在[1000]中没有一个元素,第0位为零。因此,我没有在Z为1的位置处具有零位的元素。因此,AND将永远不会为零,因此我打印1
。
问题陈述::(与HackerEarth一样)
您将获得一个数字Z和一个具有N个元素的集合S.您的工作是找到S的子集,使得给定数字的AND和该子集为零。如果此子集可以打印“是”,否则打印“否”
输入第一行包含测试用例数T.每个测试用例 包含两行,第一行包含两个数字Z和N,其中Z 给定数字,N是集合S的大小。第二行包含N. 子集S的元素。
输出对于每个测试用例,如果子集可能,则打印是 打印编号
约束:1 <= T <= 100 1 <= N <= 1000 0 <= Ai&lt; = Z <= 1000000
示例输入 3 10 2 2 0 10 3 1 1 1 5 3 1 5 3
示例输出 是 是 否
我的代码为示例输入提供了正确的答案,但在HackerEarth Submission上失败了。 请帮帮我们.. 感谢提前帮助.. :)
答案 0 :(得分:1)
你的想法也很好,但你过于复杂了一点。你能想到如何更多地简化它(做比你描述的更少的东西,但保持相同的总体思路)?请继续阅读。
我将所有n个整数存储在数组a [1000]
中
你不需要存储它们:你只会使用它们一次,所以不要费心存储它们。只需依次阅读并处理每一个。
并检查所有整数,如果它们中的任何一个在我存储在b [30]中的位置有0并且如果它们中的任何一个那么我将那个b [30]位置标记为标记,这样我就不检查那个位置再次
不需要标记或打扰不再检查。你怎么能更容易地做到这一点?对于您在位置b[i]
的数字中找到的每个零,只需递减每个i
。然后,如果yes
仅包含数字&lt; = 0。
b
现在,我们已经消除了您想要做的两件事,同时保持您的想法不变。这很好,因为如果我们减少工作量,我们做错事的机会就会减少。
我意识到这并没有回答你的代码有什么问题。我的观点是,通过更多地考虑你的想法,你可以编写更好的代码,最有可能工作。在这种情况下,你可以摆脱许多不必要的行李,减少犯错误的机会。
至于你的代码到底错在哪里,有很多东西,但最重要的部分是:
for(i=0;i<n;i++)
{
for(j=0;j<count;j++)
{
x=a[i]; <= you are setting x for each j.
You probably want this a level up, in the other loop?
if(b[j]!=-1) <= don't need this the way I described it.
{
x=x>>b[j]; <= b[j] has no bearing on how much you shift x by.
You probably meant x = x>>j?
But wait, that's wrong too, because we're in a loop,
so we'll shift by too much! Maybe x = x>>1?
// printf("New x=%d\nx&1=%d\n",x,x&1);
x==x&1; <= this doesn't do anything. Why?
What is the difference between == and =?
Do you want to use =, or move this in the if below?
if(x==0)
{
count2++;
b[j]=-1;
}
// printf("Count2=%d and Count1=%d\n",count2,count);
}
}
if(count2>=count)
{
flag=1;
break;
}
}
我建议编写一个编程教程,例如:http://www.cprogramming.com/tutorial/c-tutorial.html以及该网站上的其他人,以便在尝试解决竞赛问题之前开始使用。