你的朋友提议玩一个游戏:将写有数字的 n个纸片放入口袋中,你可以从口袋中抽取 4次纸
片,每次记下纸片上的数字后都将其放回口袋中。如果这 4个数字的和是 m,就是你赢,否
则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸
片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是 k 1 ,
k 2 , …, k n 时,是否存在抽取 4次和为 m的方案。如果存在,输出 Yes;否则,输出 No。
限制条件
1 ≤ n ≤ 50
1 ≤ m ≤ 10 8
1 ≤ k i ≤ 10 8
输入
n = 3
m = 10
k = {1, 3, 5}
输出
Yes(例如4次抽取的结果是1、1、3、5,和就是10)
求解这个问题,可由题面写出程序
#include<iostream>
using namespace std;
const int MAX_N = 50;
int main()
{
int m,n,k[MAX_N];
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>k[i];
}
bool f=false;
for(int a=0;a<n;a++)
{
for(int b=0;b<n;b++)
{
for(int c=0;c<n;c++)
{
for(int d=0;d<n;d++)
{
if(k[a]+k[b]+k[c]+k[d]==m)
f = true;
}
}
}
}
if(f)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
return 0;
}
用四重循环即可解决,当然程序运行是有时间限制的,在大多数比赛中,运行时间限制在几秒,一旦程序运行时间超过了限制,程序就会被强行结束,当做错误的解答处理,因此,在做题中要尽量寻找和思考有效的解题方法。
如本体的四重循环,如果n<50,不用1秒就可以给出答案,但是如果n<1000呢?就肯定不会通过了,所以需要寻求更有效的方法。
改进思路:上面最初循环的部分,最内侧需要做的事就是检查是否有d使得
k[a]+k[b]+k[c]+k[d]=m
通过对式子移项,得到新的等式;
k[d]=m- k[a]+k[b]+k[c]
就是说,检查k中所有元素,判断是否有m- k[a]+k[b]+k[c],可以运用二分查找
来完成。
排序O(nlogn)时间
循环O(n2logn)时间
所以该算法时间O(n3logn),对源程序改进得到:
int n,m,k[MAX_N];
bool binary_search(int x);
{
int l=0,r=n;
while(r-1>=1)
{
int i=(1+r/2);
if(k[i]==x)
return true;
else if(k[i]<x)
l=i+1;
else
r=i;
}
return false;
}
void solve()
{
sort(k,k+n);
bool f=false;
for(int a=0;a<n;a++)
{
for(int b=0;b<n;b++)
{
for(int c=0;c<n;c++)
if(binary_search(m-k[a]-k[b]-k[c]))
f=true;
}
}
if(f)
puts("Yes");
else
puts("No");
}
但是,将n=1000带入其中,发现这还是不够的,需要进一步优化,接下来,我们着眼于两个循环。和刚才同一思路,移项得
k[d]+k[c]=m- k[a]+k[b]
这种情况不能直接二分查找,需要先枚举k[c]+k[d]所得n*n种结果并排序,就可以利用二分搜索了。
排序O(n2logn)时间
循环O(n2logn)时间
所以该算法时间O(n2logn),这样也能轻松通过
int n,m,k[MAX_N];
int kk[MAX_N];
bool binary_search(int x);
{
int l=0,r=n*n;
while(r-1>=1)
{
int i=(1+r/2);
if(k[i]==x)
return true;
else if(k[i]<x)
l=i+1;
else
r=i;
}
return false;
}
void solve()
{
for(int c=0;c<n;c++)
{
for(int d=0;d<n;d++)
{
kk[c*n+d]=k[c]+k[d];
}
}
sort(kk,kk+n*n);
bool f=false;
for(int a=0;a<n;a++)
{
for(int b=0;b<n;b++)
{
if(binary_search(m-k[a]-k[b]))
f=true;
}
if(f)
puts("Yes");
else
puts("No");
}
本题需要掌握二分查找这一算法,也要有基本的设计算法的一些能力。