第一部分:二分查找
假设给出若干个(可以很多)有序的整数,请查找某个元素是否存在,比如——
2 3 4 5 6 8 12 20 32 45 65 74 86 95 100
请查找以上数列中是否存在某个整数(比如25),若有,请输出其位置,否则请输出NO~
二分查找的前提—— 数据的单调性
时间复杂度:O(logN)
例题:HDOJ-2199
地址:http://acm.hdu.edu.cn/showproblem.php?pid=2199
代码:
#include<cmath> #include<iostream> #include<cmath> #include<algorithm> #include<string> #define Y(x) 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6-y using namespace std; int n, m; int sum; int main() { double s = 0, e = 100, y; int t; cin>>t; while(t--) { s = 0; e = 100; cin>>y; if(Y(e)>=0&&Y(s)<=0) { while(e-s>1e-6) { if(Y((s+e)/2)>1e-10) e = (s+e)/2 - 1e-7; else s = (s+e)/2 + 1e-7; } printf("%.4lf\n", (s+e)/2); } else cout<<"No solution!"<<endl; } }
地址:http://acm.hdu.edu.cn/showproblem.php?pid=2899
思考:非一般的查找原函数零点,而是搜寻最值。即查询导函数的零点~
代码:
#include<cmath> #include<iostream> #include<cmath> #include<algorithm> #include<string> #define AY(x) 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*x*x-y*x #define CY(x) 42*pow(x,6)+48*pow(x,5)+21*pow(x,2)+10*x-y using namespace std; int n, m; int sum; int main() { double s, e, y; int t; cin>>t; while(t--) { s = 0; e = 100; cin>>y; while(e-s>1e-6) { if(CY((s+e)/2)>1e-10) e = (s+e)/2 - 1e-7; else s = (s+e)/2 + 1e-7; } printf("%.4lf\n", AY((s+e)/2)); } }
三分查找,略
#include<cmath> #include<iostream> #include<cmath> #include<algorithm> #include<string> using namespace std; char s[9][9]; int n, m, d1, d2, t; int me[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; bool escape; int dfs(int s1, int s2, int cnt) { int i, temp; if(escape) return 0;//已经符合条件,退出 if(s1>n||s2>m||s1<=0||s2<=0)//越界,退出 return 0; if(cnt==t&&s1==d1&&s2==d2) escape = 1; temp=(t-cnt)-abs(s1-d1)-abs(s2-d2); if(temp<0||temp%2)//剪枝一 return 0; for(i=0;i<4;i++) { if(s[s1+me[i][0]][s2+me[i][1]]!='X') { s[s1+me[i][0]][s2+me[i][1]]='X';//表示已走过 dfs(s1+me[i][0],s2+me[i][1],cnt+1); s[s1+me[i][0]][s2+me[i][1]]='.';//复原 } } return 0; } int main() { int i, j, wall; int s1, s2; while(cin>>n>>m>>t,n+m+t) { escape = 0; memset(s,'X',81*sizeof(char)); wall = 0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) { cin>>s[i][j]; if(s[i][j]=='S') { s1=i; s2=j; } else if(s[i][j]=='D') { d1=i; d2=j; } else if(s[i][j]=='X') wall++; } if(n*m-wall<=t) //剪枝二 { cout<<"NO"<<endl; continue; } s[s1][s2]='X';//初始位置不可再走 dfs(s1,s2,0); puts(escape?"YES":"NO"); } return 0; }
嘛, 剪枝要详细点写
剪枝一
那么设所在位置 (s1,s2) 与 目标位置 (d1,d2)
如果abs(d1-s1)+abs(d2-s2) 为偶数,则说明 abs(d1-s1)+和 abs(d2-s2)的奇偶性相同,需要走偶数步.
如果abs(d1-s1)+abs(d2-s2)为奇数,那么说明 abs(d1-s1)和 abs(d2-s2)的奇偶性不同,需要走奇数步.
解为 abs(d1-s1)+abs(d2-s2)的奇偶性就确定了所需要的步数的奇偶性!!
而 (t-cnt)表示剩下还需要走的步数,由于题目要求要在 t时恰好到达,
那么(t-cnt)与abs(d1-s1)+abs(d2-s2) 的奇偶性必须相同
因此 temp=t-cnt- abs(d1-s1)+abs(d2-s2)必然为偶数!
剪枝二
这个比较简单也没什么大用, 约定时刻走过的方块数加上墙的个数应当小于总区域面积。
inline double Y(double x) { return SomethingAboutX; } const double eps = 1e-6; double BinSearch(double start, double end, double K ) { double mid; if(fabs(Y(start)-K)<eps) return start; if(fabs(Y(end)-K)<eps) return end; while(fabs(end-start)>eps) { mid = (start + end)/2 ; if(Y(mid)-K>eps) end = mid - eps; else start = mid + eps; } return (start+end)/2; }