抽 签
你的朋友提议玩一个游戏:将写有数字的 n 个纸片放入口袋中,你可以从口袋中抽取 4 次纸
片,每次记下纸片上的数字后都将其放回口袋中。如果这片,每次记下纸片上的数字后都将其放回口袋中。如果这 4 个数字的和是 m,就是你赢,否则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是 k1,k2, … , kn时,是否存在抽取 4 次和为 m 的方案。如果存在,输出 Yes;否则,输出 No。
1 ≤ n ≤ 50
1 ≤ m ≤ 108
1 ≤ ki ≤ 108
由于本题有1 <= n <= 50这个条件,我们可以采用四重循环,不用一秒就可以得到答案,时间复杂度为0(n4)。
代码如下:
/*
51nod 1000 A+B
作者:blue
Time: 2018\6\10 11:05
*/
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int n;
int m;
int a[50];
bool find = false;
cin>>n>>m;
for(int i = 0; i < n; i++)
{
cin>>a[n];
}
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
for(int k = 0; k < n; k++)
{
for(int l = 0; l < n; l++)
{
if(m == a[i]+a[j]+a[k]+a[l])
{
find = true;
}
}
}
}
}
if(find == false)
{
cout<<"No"<<endl;
}
else
{
cout<<"Yes"<<endl;
}
return 0;
}
但是当n的范围不在局限在50之内的时候,对于大数据,四重循环的时间复杂度会急剧上升,因此我们需要寻找另外一种更为高效的方法。
我们可以换一种思维,把寻找ka + kb + kc + kd = m的方程改为kd = m - ka - kb - kc,这样我们就可以从数组中寻找kd,而寻找kd的方法我们可以简化,采用二分查找的方式,时间复杂度降为0(n3logn)。
代码如下:
/*
51nod 1000 A+B
作者:blue
Time: 2018\6\10 11:05
*/
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool binary_search(int a, int n, int x)
{
int l = 0,r = n;
//反复执行直到范围为空
while(r >= 2)
{
int i = (1+r) / 2; //中间
if(a[i] == x) return true;
else if(k[i] < x) l = i+1;
else r = i;
}
return false;
}
int main()
{
int n;
int m;
int a[50];
bool find = false;
cin>>n>>m;
for(int i = 0; i < n; i++)
{
cin>>a[n];
}
sort(a,a+n); //排序
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
for(int k = 0; k < n; k++)
{
if(binary_search(m - a[i] - a[j] - a[k]))
{
find = true;
}
}
}
}
if(find == false)
{
cout<<"No"<<endl;
}
else
{
cout<<"Yes"<<endl;
}
return 0;
}