您的位置:首页 > 其它

HDU 2141 Can you find it?【二分】

2015-07-30 19:03 405 查看

Can you find it?

Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/10000 K (Java/Others)

Total Submission(s): 17160 Accepted Submission(s): 4358



[align=left]Problem Description[/align]
Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.

[align=left]Input[/align]
There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there
are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.

[align=left]Output[/align]
For each case, firstly you have to print the case number as the form "Case d:", then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print "YES", otherwise print
"NO".

[align=left]Sample Input[/align]

3 3 3
1 2 3
1 2 3
1 2 3
3
1
4
10


[align=left]Sample Output[/align]

Case 1:
NO
YES
NO


[align=left]Author[/align]
wangye

[align=left]Source[/align]
HDU 2007-11 Programming Contest

题意:

输入三组数,再输入一个数,然后在每一组选取一个数,加起来,看看是否能够等于这个数,如果等于则输出yes,否则,输出no。

思路:

但是要注意超时,如果方法不当会导致超时现象,并且要注意数组d应该开成501*501这么大才够用,否则会出现因数组开的小而出错。当选用二分法的时候,要对数多的选用二分法,这一点也要注意,否则会超时!

这道题有多种做法,首先我们最容易想起来的就是①四层for循环:也就是输入一个数,然后通过遍历的方法查看a1[i]+a2[j]+a3[k]中是否有等于输入的那个数的情况,如果有,则输出yes,否则输出no,但是不幸的是这种方法太笨了,会因为循环次数过多而超时;然后通过学习二分法,我终于能够有简单的方法来解答这一个问题了:②就是通过双重循环将前两个集合中选取元素加到一起,然后对得到的一组数进行排序,然后将输入的那个数减去a3得到v[j],用二分法在得到的那组数所组成的集合中找是否有和这个v[j]相同的数如果有则输出yes,否则输出no;(在这里面我犯了一个大
错误就是在二分的时候将输入的那个数减去d[j]了,然后对数组a进行二分了,因为d数组里面的元素有501*501个,太大了,而a3中的元素才501个,从而导致循环次数过多而超时!),在这一点坑我了好久!

代码:

/*
刚开始的超时代码!
*/
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

int a1[505],a2[505],a3[505],y[255000],d[255000],v[255000];
int cmp(int u,int v)
{
return u>v;
}

int main()
{
int a,b,c,t=0,s,u;
while(scanf("%d%d%d",&a,&b,&c)!=EOF)
{
t++;
printf("Case %d:\n",t);
for(int i=0;i<a;i++)
scanf("%d",&a1[i]);
for(int i=0;i<b;i++)
scanf("%d",&a2[i]);
for(int i=0;i<c;i++)
scanf("%d",&a3[i]);
u=0;
for(int i=0;i<b;i++)
for(int j=0;j<c;j++)
d[u++]=a2[i]+a3[j];
sort(d,d+u,cmp);
scanf("%d",&s);
int e,k;
int left,right,mid;

for(int i=0;i<s;i++)
{
scanf("%d",&y[i]);
for(int j=0;j<u;j++)
{
v[j]=y[i]-d[j];
k=0;
left=0;right=a-1;
while(left<=right)
{
mid=(left+right)/2;
if(a1[mid]<v[j])  left=mid+1;
else if(a1[mid]>v[j])right=mid-1;
else if(a1[mid]==v[j])
{
k++;
break;
}
}
}
if(k>0)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}


这个代码就是因为选错二分对象而导致出错,后来听别人说改成函数的形式进行调用就会解决这个问题,我尝试了还是错的,代码如下:
/*
将其改成函数的形式!
*/
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

int a1[505],a2[505],a3[505],y[255000],d[255000],v[255000];
int right,left,mid;
int i,j,k;
int a,b,c,t,s,u;
int cmp(int u,int v)
{
return u>v;
}

int erfenfa(int x)
{
left=0;right=a-1;
while(left<=right)
{
mid=(left+right)/2;
if(a1[mid]<x)  left=mid+1;
else if(a1[mid]>x)right=mid-1;
else if(a1[mid]==x)
{
k++;
break;
}
}
return 0;
}

int main()
{
t=0;
while(scanf("%d%d%d",&a,&b,&c)!=EOF)
{
t++;
printf("Case %d:\n",t);
for(int i=0;i<a;i++)
scanf("%d",&a1[i]);
for(int i=0;i<b;i++)
scanf("%d",&a2[i]);
for(int i=0;i<c;i++)
scanf("%d",&a3[i]);
u=0;
for(int i=0;i<b;i++)
for(int j=0;j<c;j++)
d[u++]=a2[i]+a3[j];
sort(d,d+u,cmp);
scanf("%d",&s);
for(int i=0;i<s;i++)
{
scanf("%d",&y[i]);
for(int j=0;j<u;j++)
{
v[j]=y[i]-d[j];
k=0;
erfenfa(v[j]);
if(k>0)
break;
}
if(k>0)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}


最后我找到了错误的根源不在于是否是调用函数,还是直接将功能写到函数里面,而是二分对象选错了,改正后的代码如下:
/*
将二分对象转换为数组d,因为数组d里面的元素有501*501个
*/
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
//数组的大小一定得确定好,由于后面有for循环所以元素个数应该是相乘的关系!
int a1[505],a2[505],a3[505],y[255000],d[255000],v[255000];
int right,left,mid;//将其写成函数的形式就要将变量写成全局变量
int i,j,k;
int a,b,c,t,s,u;

int cmp(int u,int v)//按照从大到小的顺序排序
{
return u>v;
}

int erfenfa(int x)//二分法查找的函数
{
left=0;right=u-1;
while(left<=right)
{
mid=(left+right)/2;
if(d[mid]<x)  right=mid-1;
else if(d[mid]>x) left=mid+1;
else if(d[mid]==x)
{
k++;
break;
}
}
return 0;
}

int main()
{
t=0;
while(scanf("%d%d%d",&a,&b,&c)!=EOF)
{
t++;
printf("Case %d:\n",t);
for(int i=0;i<a;i++)//输入数据
scanf("%d",&a1[i]);
for(int i=0;i<b;i++)
scanf("%d",&a2[i]);
for(int i=0;i<c;i++)
scanf("%d",&a3[i]);
u=0;//用来保存d的下标
for(int i=0;i<b;i++)//将a2,a3所有和的可能都写到数组d中
for(int j=0;j<c;j++)
d[u++]=a2[i]+a3[j];
sort(d,d+u,cmp);//对数组d进行排序
scanf("%d",&s);//要查s个数是否符合题意
for(int i=0;i<s;i++)
{
scanf("%d",&y[i]);//要判断的数
k=0;
for(int j=0;j<a;j++)
{
v[j]=y[i]-a1[j];//要查找的数
erfenfa(v[j]);
if(k>0)//如果大于0,说明找到相同的元素了
break;
}
if(k>0)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}


这个ac之后,我又将之前实现二分功能的函数写到主函数内部的那个程序修改了一下也AC了,代码如下:

/*
还是原来的没有把二分专门变成函数,提到main函数前面,但是改了一点就是
将二分对象换成数组d了!
*/

#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

int a1[505],a2[505],a3[505],y[255000],d[255000],v[255000];
int cmp(int u,int v)
{
return u>v;
}

int main()
{
int a,b,c,t=0,s,u;
while(scanf("%d%d%d",&a,&b,&c)!=EOF)
{
t++;
printf("Case %d:\n",t);
for(int i=0;i<a;i++)
scanf("%d",&a1[i]);
for(int i=0;i<b;i++)
scanf("%d",&a2[i]);
for(int i=0;i<c;i++)
scanf("%d",&a3[i]);
u=0;
for(int i=0;i<b;i++)
for(int j=0;j<c;j++)
d[u++]=a2[i]+a3[j];
sort(d,d+u,cmp);
scanf("%d",&s);
int e,k;
int left,right,mid;

for(int i=0;i<s;i++)
{
scanf("%d",&y[i]);
for(int j=0;j<a;j++)
{
v[j]=y[i]-a1[j];
k=0;
left=0;right=u-1;
while(left<=right)
{
mid=(left+right)/2;
if(d[mid]<v[j])  right=mid-1;
else if(d[mid]>v[j]) left=mid+1;
else if(d[mid]==v[j])
{
k++;
break;
}
}
if(k>0)
break;
}
if(k>0)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}


经过挫折的修改,终于ac了,通过做这道题,我觉得以后用二分法的时候要选取好要二分的对象,要将元素比较多的进行二分,这样才会更加节省时间;还有在for循环使用之后那个元素的个数应该是原来的元素个数相乘而不是想加!
例如:
k=0;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
a[k++]=i*j;
数组a中的元素的个数应该是5*5个!!!!!!!!!!!!!!!!!

搜索
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: