抽签问题(C++)—合二为一(上)
你的朋友提议玩一个游戏:把写有数字的n个纸片放入一个袋子里,
你可以从中抽取4张纸片,每次抽取后把纸片放回到袋子里,如果
抽取的4张纸片上的数字和为m,就算你赢,否则你输,抽了很多
次,结果你完败,那么我可以胜利吗?假设纸牌上的数字依次为k1,
k2,k3,k4,….ki,试写一个程序判断你是否有胜利的可能
限制条件:
n(1,50)
m(1,10^8)
ki(1,10^8)
const int MAX_N = 50;
int main(){
//是否查找到符合条件的组合的标志
bool f=false;
int n,m;
int k[MAX_N];
//从标准输入输入
scanf("%d %d",&n,&m);
for(i = 0;i<n;i++){
scanf("%d",&k[i]);
}
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(m==k[a]+k[b]+k[c]+k[d])
f=true;
}
}
}
}
//从标准输出输出
if(f)
//printf("%d/n",yes);
puts("Yes");
else{
//printf("%d/n",no);
puts("no");
}
}
是否觉得超级简单,那么问题来了,当n = 1000时,我们的算法复杂度1000^3,我们需要降低其复杂度
如何去做,如何结合二分法降低其复杂度
二分法:将数据从小到大排列,取中间数,如果比中间数大,在后半部分查找,如果比中间数小,在前半部分查找
int n,m;
int k[MAX_N];
bool f = false;
bool binary_search(int x)
//k[l],k[l+1],k[l+2]....k[r-1]
{
while(r-1>1){
int l=0;
int r=n;
int i=(l+r)/2;
if(x>k[i])
l=i+1;
else if(x==k[i])
return true;
else
r=i;
}
return false;
}
void solve(){
sort(k,k+n);
for(a = 0;a<n;a++){
for(b = 0;b<n;b++){
for(c = 0;c<n;c++){
if(binary_search(m-k[a]-k[b]-k[c])){
f = true;
}
}
}
}
if(f)
puts("Yes");
else
puts("no");
}
第一次优化算法后,让我们来看看复杂度
排序nlogn
循环n^3logn
n^3logn比nlogn大,所以复杂度为n^3logn