读书笔记<程序设计>|抽签
抽签
你的朋友提议玩一个游戏:将写有数字的n个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片的数字后都将其放回口袋中。如果这4个数字的和是m,就是你赢,否则,就是你的朋友赢。你挑战了好几回合,结果一次也没有赢过,于是努而撕破口袋,取出所有的纸片,检查自己是否真的有赢的可能性。请编写一个程序,判断当纸片上的所写的数字是k1,k2,……,kn时,是否存在抽取4次和为m的方案。如果存在,输出Yes;否则,输出No。
限制条件:
1<=n<=50
1<=m<=10^8
1<=ki<=10^8
一般思路:
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> int main(int argc, char *argv[]) { int m,n,i,j,k,l,a[50]; bool flag=false;//标志是否存在 scanf("%d",&n); scanf("%d",&m); for(i=0;i<n;i++){ scanf("%d",&a[i]); } for(i=0;i<n;i++){ for(j=0;j<n;j++){ for(k=0;k<n;k++){ for(l=0;l<n;l++){ if(a[i]+a[j]+a[k]+a[l]==m){ flag=true; } } } } } if(flag)printf("%s\n","Yes"); else printf("%s\n","No"); system("PAUSE"); return 0; }
注意要点:
对于bool类型的未定义解决办法参考:http://cprogrammer.blog.163.com/blog/static/18340047620113993850877/
原因:http://blog.csdn.net/xiaohaijiejie/article/details/43973237
个人体会
1.由于bool不是c的关键字,需要另外自申明typedef enum __bool{false,true}bool;或者利用其他的函数库#include<stdbool.h>
2.时间复杂度为o(n^4)
3.考虑复杂度是否可以变为o(n^3logn)、o(n^2logn)等。
延伸1:利用二分法实现n^3logn的时间复杂度。
思路:先利用对数组进行排序,然后对四个数中的m-a[i]-a[j]-a[k]进行二分法查找。排序需要nlogn,二分查找需要n^3logn,所以需要n^3logn。
首先需要明确的是我们利用的是c库中现有的函数sort():此函数有两种用法:
(1)sort(RandomIt first,RandomIt last):其中变量的类型可以是人意的类型,int,char,list,vector……。
(2)sort(RandmIt first,RandomIt last,Compera comp):其中comp是可以自定义的比较函数。
顺便提一下qsort函数,使不同于sort函数的,从另一个角度来讲,sort函数包括qsort()函数,sort函数包含qsort函数、堆排序、插入排序。
基本代码如下(其中由于编译器的问题我分别用vs2013和devc++v4.9.9.2版本比较老,其中代码中的细节需要依据具体的编译器进行改动):
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <algorithm> #include <iostream> int a[1000000];//很多数,这样sort函数的性能才能体现出来。 int m, n;//方便binaray_find函数的利用 bool binaray_find(int x){ int i = 0, j = n; for (i = (i + j) / 2; i +1<= j;){ if (a[i] == x)return true; else if (x>a[i]){ i = (i + j) / 2+1; } else{ j = (i + j) / 2; } } return false; } int main(int argc, char *argv[]) { int i, j, k; bool flag = false; scanf_s("%d%d",&n,&m); for (i = 0; i < n; i++){ scanf_s("%d",&a[i]); } std::sort(a, a + n); for (i = 0; i < n; i++){ printf("%d",a[i]); } for (i = 0; i<n; i++){ for (j = 0; j<n; j++){ for (k = 0; k<n; k++){ if (binaray_find(m - a[i] - a[j] - a[k]))flag = true; } } } if (flag)printf("%s", "Yes"); else printf("%s", "No"); system("PAUSE"); return 0; }
主要是由于c中没有现成的sort函数,所以代码中含有了c++的成分。
个人体会:整体的思路还是比较简单的,但是对于细节的实现binaray_find()函数的实现还需要细细琢磨。
延伸2:利用二分法实现o(n^2logn)
同样的思路,只是把kc+kd=m-ka-kb;预先枚举出kc+kd的所有的n^2个数字并排好序,以便利用二分法搜索了。
#include <cstdlib> #include <iostream> #include <algorithm> #define Num 10000 using namespace std; int m, n, aa[Num*(Num + 1) / 2], a[Num]; bool binaray_find(int x){ int l = 0, r = n*(n + 1) / 2; while (r - l >= 1){ int i = (r + l) / 2; if (aa[i] == x)return true; else if (aa[i]<x)l = i + 1; else r = i; } return false; } int main(int argc, char *argv[]) { int i, j; cin >> n >> m; bool flag = false; for (i = 0; i<n; i++){ cin >> a[m]; } for (i = 0; i<n; i++){ for (j = i; j<n; j++){ aa[j + i*(n - i)] = a[i] + a[j]; } } sort(aa, aa + n*(n + 1) / 2); for (i = 0; i<n; i++){ for (j = 0; j<n; j++){ if (binaray_find(m - a[i] - a[j]))flag = true; } } if (flag)cout << "Yes" << endl; else cout << "No" << endl; system("PAUSE"); return EXIT_SUCCESS; }
今天先这样,代码确实有问题