【题目描述】:
将写有数字的n个纸片放入口袋,抽取四次,每次抽取后记下数字后放回纸片,判断这四个数字和是否有可能为m?
限制条件:
1<=n<=50
1<=m<=10(8)
1<=ki<=10(8)
【分析】:
因为是 4张,且是又放回抽取,假设数字是a,b,c,d;
因此前两次抽取的值的和的有可能的情况(a+b) 和 后两者抽取的值的和的情况(c+d)是一样的,那么做题思路就出来了:
先用一个二维数组记录出所有的两种数字组合的情况(相当于列举抽取的a+b的值)
再用m-(a+b)表示(c+d),在二维数组中找寻m-(a+b),如果存在(找得到),那么说明就可以为m,否则就说明这种情况不符合
查找的时候,先对二维数组排序,采用二分查找法,减少时间复杂度
总体:算法复杂度为n²log(n)
代码
#include<iostream>
#include<algorithm>
#define N 1000+5
using namespace std;
int n,m;
int a[N];
int b[N*N];//用一维数组 表达二维数组
bool search(int x) {
int l=0,r=n*n-1;
while(l<r) {
int i=(l+r)/2;//二分查找
if(b[i]==x)
return true;
if(b[i]<x)
l=i+1;
else
r=i;
}
return false;
}
void solve() {
for(int i=0; i<n; i++) { //行
for(int j=0; j<n; j++) { //列
b[i*n+j]=a[i]+a[j];//每个两个纸片的组合均计算包含了
}
}
sort(b,b+N*N);//排序
bool c=false;
for(int i=0; i<n; i++) {
for(int j=0; j<n; i++) {
if(search(m-a[i]-a[j])) {//查找剩余的值是否出现在组合情况中
c=true;
break;
}
}
}
/*
上述代码修改成这样也可以
for(int i=0; i<n*n; i++) {
if(search(m-b[i])) {
c=true;
break;
}
}
*/
if(c==true)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
}
int main() {
cin>>n>>m;
for(int i=0; i<n; i++)//输入卡片上的值
cin>>a[i];
solve();
}